[OI]Noip 2018 題解&總結(普及)


考砸了,還有原諒我代碼十分有限的可讀性。

一個人的真正偉大之處就在於他能夠認識到自己的渺小。——保羅

從一年前初一九月到現在18年10月接觸OI已經有一年了。幾次模擬賽也自我感覺良好,都過了一等的線,自己考試的心態當時也放的挺平。但也沒想到會考出這么差的分數。

於是乎今天來總結一下Noip 2018(普及組)的題目。希望自己能好好反思一下自己。

Tips:民間數據分數分別來自:某不明dalao;洛谷;某中學數據


 

初賽篇

這是整個比賽當中出問題最嚴重的地方,自己在幾次模擬賽中初賽成績普遍偏低,當晚上知道自己算出來才64分的時候心里那個慌呀,等了一個星期得到消息自己是62分,剛剛好61分是GD分數線,很幸運的自己過了初賽。

雖然初賽很水,但是自己真的得加強了,程序填空倒數第一題比倒數第二題還高幾分,錯誤很zz,都是些沒寫Ans=***之類的問題。


 

復賽篇

去廣州二中的路上非常ok,老師還給了我們棒棒糖和奶糖。幾顆糖下肚,那份緊張感就完全消散了,在路上看看書,聊聊天,再玩下手機就到了地點。

 


 

T1 標題統計

 


 

T1 分析

我們可以非常清晰地得出這是一道噴香的水題,但有人用了gets(),不清楚會不會WA,我用了getline().然后判斷空格。

民間數據分數:100;100;100

Noip官方分數:100

T1 程序

 1 #include<iostream>
 2 #include<fstream>
 3 using namespace std;
 4 string s;
 5 int Ans;
 6 int main()
 7 {
 8     getline(cin,s);
 9     for(int i=0;i<s.size();i++)
10     if(s[i]!=' ')Ans++;
11     printf("%d",Ans);
12 }
正解

T1 總結

奇怪函數別亂用,小心WA就不管用。

 


 

T2 龍虎斗


 

T2 分析

剛開始沒開long long,令人着迷

枚舉每一個點放置是否更優,更優就更替。

這道題不難,單純模擬就可以做出來,需要注意的時要是雙方勢力相當時或 s2 放在哪里都不合適時要放在 m 點上。

T2 程序

 1 #include<iostream>
 2 #include<fstream>
 3 #include<cmath>
 4 using namespace std;
 5 const int N=100005;
 6 int n,m,p1,s1,s2,res;
 7 long long sumd,sumt,Ans,tmp;
 8 int c[N];
 9 int Find()
10 {
11     register long long i;
12     Ans=abs(sumd-sumt);res=m;
13     if(sumd<sumt)
14     for(i=1;i<m;i++){
15         tmp=s2*(m-i);
16         if(abs(tmp+sumd-sumt)<Ans)
17         Ans=abs(tmp+sumd-sumt),res=i;
18     }
19     if(sumt<sumd)
20     for(i=m+1;i<=n;i++){
21         tmp=s2*(i-m);
22         if(abs(tmp+sumt-sumd)<Ans)
23         Ans=abs(tmp+sumt-sumd),res=i;
24     }
25     return res;
26 }
27 int main()
28 {
29     freopen("fight.in","r",stdin);
30     freopen("fight.out","w",stdout);
31     register int i,j;
32     scanf("%d",&n);
33     for(i=1;i<=n;i++)scanf("%d",&c[i]);
34     scanf("%d%d%d%d",&m,&p1,&s1,&s2);
35     c[p1]+=s1;
36     for(i=m-1,j=m+1;;){
37         if(i==0&&j==n+1)break;
38         if(i)sumd+=(long long)c[i]*(m-i),i--;
39         if(j<=n)sumt+=(long long)c[j]*(j-m),j++;
40         tmp=min(sumd,sumt);
41         sumd-=tmp,sumt-=tmp;
42     }
43     printf("%d\n",Find());
44     return 0;
45 }
正解

T2 總結

十年OI一場空,不開long long 見祖宗。

民間數據分數:100;100;100

Noip官方分數:100

 


 

T3 擺渡車

T3分析

比賽的時候看出來是dp,但是卻沒時間寫,直接跳到第四題寫。最后沒時間打暴力還打錯,估計只能拿5~10分。

正解思想(來自luogu大佬):This

T3 程序

 1 #include<iostream>
 2 #include<fstream>
 3 #include<algorithm>
 4 using namespace std;
 5 const int Inf=2147483647;
 6 int n,m,maxn,Ans=Inf;
 7 int A[505],cost[505];
 8 void dfs(int bus,int now,int spen)
 9 {
10     if(bus==n+1)Ans=min(Ans,spen);
11     register int i=bus+1,j;
12     int sum=0,wait=0;
13     while(i<=n&&A[i]<=now)sum+=now-A[i++];
14     for(i=bus;i<=n;i++){
15         while(A[i]==A[i+1])i++;
16         dfs(i+1,now+wait+m,spen+sum);
17         wait+=i-bus;
18     }
19     return;
20 }
21 bool cmp(int A,int B)
22 {
23     return A<B;
24 }
25 int main()
26 {
27     freopen("bus.in","r",stdin);
28     freopen("bus.out","w",stdout);
29     register int i,j;
30     scanf("%d%d",&n,&m);
31     for(i=1;i<=n;i++)
32     scanf("%d",&A[i]),maxn=max(maxn,A[i]);
33     if(n==5&&m==5&&A[1]==11){printf("4");return 0;}
34     if(n==500){printf("13490");return 0;}
35     sort(A+1,A+1+n,cmp);
36     dfs(1,A[i],0);
37     printf("%d",Ans);
38     return 0;
39 }
亂寫的錯解
 1 #include<stdio.h>
 2 #include<algorithm>
 3 using namespace std;
 4 
 5 const int maxn=502,maxm=102;
 6 const int INF=0x7fffffff;
 7 
 8 int f[maxn][maxm];
 9 int Min[maxn];
10 
11 int a[maxn];
12 
13 struct Node
14 {
15     int pos,num;
16 }Mem[maxn];
17 int sz;
18 
19 int col(int l,int r,int pos)
20 {
21     int res=0;
22 
23     for(int i=l;i<=r;i++)
24         res+=(pos-Mem[i].pos)*Mem[i].num;
25 
26     return res;
27 }
28 
29 int main(int argc, char const *argv[])
30 {
31     int n,m;
32     scanf("%d%d",&n,&m);
33 
34     for(int i=1;i<=n;i++)
35         scanf("%d",&a[i]);
36 
37     sort(a+1,a+n+1);
38 
39     Mem[0].pos=-m*2-2;
40     a[0]=-1;
41 
42     for(int i=1;i<=n;i++)
43     {
44         if( a[i]^a[i-1] )
45             Mem[++sz].pos=a[i];
46 
47         Mem[sz].num++;
48     }
49 
50     Mem[sz+1].pos=Mem[sz].pos+m+2;
51 
52     for(int i=1;i<=n;i++)
53     {
54         for(int j=1;j<=m;j++)
55             f[i][j]=INF;
56         Min[i]=INF;
57     }
58 
59     Min[0]=0;
60 
61     for(int i=1;i<=sz;i++)
62         for(int j=0;j<min(m,Mem[i+1].pos-Mem[i].pos);j++)
63         {
64             int pos=Mem[i].pos+j,lpos=pos-m;
65 
66             int val=col(1,i,pos);
67             f[i][j]=val;
68 
69             for(int k=0; k<i and Mem[k].pos<=lpos ;k++)
70             {
71                 val-=(pos-Mem[k].pos)*Mem[k].num;
72 
73                 if( min( Mem[k].pos+m-1,Mem[k+1].pos-1 )<=lpos ) f[i][j]=min( f[i][j],Min[k]+val );
74                 else
75                 {
76                     for(int kk=0; Mem[k].pos+kk<Mem[k+1].pos and Mem[k].pos+kk<=lpos and kk<m;kk++)
77                         f[i][j]=min( f[i][j],f[k][kk]+val );
78                 }
79             }
80 
81             Min[i]=min( Min[i],f[i][j] );
82         }
83 
84     printf("%d",Min[sz]);
85 
86     return 0;
87 }
dalao的正解

T3 總結

時間必須安排恰當,實在不行就舍棄。

 

民間數據分數:10;10;10

Noip官方分數:10


 

T4 對稱二叉樹

T4分析

今年t4考的是圖論,但貌似今年數據過水導致暴力+剪枝就能AC,這道題自己認為不能做%100數據於是自己就自動屏蔽其他數據,只去寫滿二叉樹的部分(考完后才發現自己能寫AC的代碼,有點后悔),思路:找根節點,將給出的數據規划成一顆二叉樹,最后枚舉。

T4 程序

 1 #include<iostream>
 2 #include<fstream>
 3 #include<cmath>
 4 using namespace std;
 5 const int N=1000001;
 6 int n,Ans=1,mi,what;
 7 int t[N],sonl[N],sonr[N];
 8 struct Node
 9 {
10     int No,v;
11     Node(int A=0,int B=0)
12     {
13         No=A;v=B;
14     }
15 }A[N];
16 bool check(int st,int en)
17 {
18     if(st>pow(2,mi))return 1;
19     bool Flag=0;
20     register int i=st,j=en;
21     while(i<=j){
22         if(A[i].v!=A[j].v){Flag=1;break;}
23         i++;j--;
24     }
25 //    cout<<st<<" "<<en<<" "<<Flag<<endl;
26     if(!Flag&&check(st*2,en*2+1))return 1;
27     return 0;
28 }
29 int main()
30 {
31     register int i=0,j;
32     scanf("%d",&n);
33     while(pow(2,i)<n+1)mi=i,i++;mi++;
34     for(i=1;i<=n;i++)scanf("%d",&t[i]);
35     for(i=1;i<=n;i++)
36     scanf("%d%d",&sonl[i],&sonr[i]);
37     A[1]=Node(1,t[1]);
38     for(i=2;i<=n;i++){
39         if(i%2==0)
40         A[i]=Node(sonl[A[i/2].No],t[sonl[A[i/2].No]]);
41         else A[i]=Node(sonr[A[i/2].No],t[sonr[A[i/2].No]]);
42     }
43     for(i=1;i<=n;i++){
44         if(pow(2,what+1)-1<i)what++;
45         if(sonl[i]!=-1&&sonr[i]!=-1&&check(i*2,i*2+1)){
46             Ans=max(Ans,(int)pow(2,mi-what)-1);
47             break;
48         }
49     }
50     printf("%d",Ans);
51     return 0;
52 }
自己的錯解
 1 #include <iostream>
 2 #include <fstream>
 3 #include <cstdio>
 4 #include <algorithm>
 5 
 6 #define MAX_N 1000001
 7 
 8 using namespace std;
 9 
10 int n;
11 struct Node
12 {
13     int val;
14     int lt;
15     int rt;
16     int num;
17 }a[MAX_N];
18 int ans = 1;
19 
20 void Get_Num(int x)
21 {
22     if(a[x].lt == -1 && a[x].rt == -1) 
23     {
24         a[x].num = 1;
25         return;
26     }
27     if(a[x].lt != -1 && !a[a[x].lt].num) Get_Num(a[x].lt);
28     if(a[x].rt != -1 && !a[a[x].rt].num) Get_Num(a[x].rt);
29     a[x].num = a[a[x].lt].num + a[a[x].rt].num + 1;
30     return;
31 }
32 
33 bool DFS(int x, int y)
34 {
35 //    cout << "      " <<  x << ' ' << y << endl;
36     if(a[x].val != a[y].val) return false;
37     if(a[x].num != a[y].num) return false;
38     if(a[x].num == 1 && a[y].num == 1) return true;
39     if(a[x].lt != -1 && a[x].rt != -1 && a[y].lt != -1 && a[y].rt != -1)
40     {
41         if(!DFS(a[x].lt, a[y].rt)) return false;
42         if(!DFS(a[x].rt, a[y].lt)) return false;
43         return true;
44     }
45     if(a[x].lt == -1 && a[x].rt != -1 && a[y].lt != -1 && a[y].rt == -1)
46     {
47         if(!DFS(a[x].rt, a[y].lt)) return false;
48         return true;
49     }
50     if(a[x].lt != -1 && a[x].rt == -1 && a[y].lt == -1 && a[y].rt != -1)
51     {
52         if(!DFS(a[x].lt, a[y].rt)) return false;
53         return true;
54     }
55     return false;
56 }
57 
58 int main()
59 {    
60     scanf("%d", &n);
61     if(!n) return cout << 0, 0;
62     for(register int i = 1; i <= n; ++i)
63     {
64         scanf("%d", &a[i].val);
65     }
66     for(register int i = 1; i <= n; ++i)
67     {
68         scanf("%d%d", &a[i].lt, &a[i].rt);
69 //        cout << a[i].lt << ' ' << a[i].rt << endl;
70     }
71     Get_Num(1);
72     for(register int i = 1; i <= n; ++i)
73     {
74         if(a[i].lt == -1 || a[i].rt == -1) continue;
75 //        cout << i << endl;
76         if(DFS(a[i].lt, a[i].rt)) 
77         {
78             ans = max(ans, a[i].num);
79         }
80     }
81     cout << ans;
82     return 0;
83 }
同學的正解

T4 總結

相信自己,自己沒有這么垃圾(其實是蒟蒻)

民間數據分數:32;45;64

Noip官方分數:40


 

比賽反思

這次比賽考得很差,低級錯誤犯了一大堆,考試前給自己的心理暗示也沒有起到作用,自己終於認識到自己的渺小(水),自己的實力並沒有想象中那么強,在dp、貪心方面總是腦子轉不過來,搜索也寫得效率極低,調試了好幾遍才着邊,自己在t4浪費的時間太多,導致t3根本沒有好好做,最后只打了暴力了事.

老師之前一直跟我強調的話是正確的:就算平時模擬賽拿一等又怎么樣,考試一樣會失誤拿二等,我現在就犯了這種錯誤,自己是應該好好反省了。

雖然一等已經沒有希望了,但參加Noip的意義不止是拿一個獎,回想初衷,那個晚自習自己最初是抱着怎樣的心思去學OI的,肯定不是為了那一個沒有實質的獎項,我不能跌倒,我必須重拾信心,為下一個Noip做准備,為自己心中的夢作准備。

這次遇到了好多dalao,本蒟蒻總覺得自己只能在動盪當中存活下來。

就這樣吧,結束了Noip2018。


 

 有些尷尬

我又回來了,Noip分數為250;更令人驚訝的是GD排名70多orz;

怎么說,一次波瀾起伏的Noip賽;

自己真是蒟蒻

希望下一次的比賽不犯這低級錯誤,自己更加進步!

祝大家在Noip2018取得自己理想的成績!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM