NOIP2017
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NOIP2017相关的知识,希望对你有一定的参考价值。
期中考爆炸之后noip接着炸,怎么这么惨啊qwq。
Day 0
像以前一样坐高铁,车上也没打什么代码,下午到广州。
然后就在酒店打了几个模版,也没怎么颓废。晚上写了cf教育场的ABC,D是一道组合数不会写,然后写了一下前几年pj的一些签到题(被回文日期虐哭QAQ),然后莫名熬到一点多才睡觉。
Day1
早早起床打了几个模版,都是1A,rp++。听说QZZ昨晚已经把教育场ABCDE都A了(吓哭)。
吃完早餐接着打模版,然后就一个上午过去了。中午大概睡了半小时,然后就坐地铁到广州六中。
QZZ:我五分钟AK!!!
拍了一下集体照,然后就找了一下试室,诶什么鬼我试室座位号108?
和初二zc在一个试室。
考前洗了把脸,清醒很多。
lz走过来:“不要紧张balabala。。”
我:“嗯....”。
我也惊讶自己一点都不紧张。。难道我心态有这么好?(不存在的...)
进试室,然后发现座位号是18QAQ,喝了口水,然后无所事事。。
啥?密码是啥?
蛤?怎么又错误?
蛤?怎么你们都知道密码?
蛤?怎么你们都开始看题了?
密码好几遍都听不清。。。
然后监考员拿张纸写着密码让我抄在草稿纸上。。
怎么还是开不了啊。。。
哦!没大写==(喷血.jpg)
然而已经过去5min了。。。
T1,诶这个好像要double,怎么办怎么办c++double我有点慌啊。。。
哦!10的整数倍。。(喷血.jpg*2)
T2,啊难道要字符串?哦,直接膜就可以了啊。。
T3,宽搜?好像不太难也不太容易。。
T4,x[i]单调递增,二分答案?怎么check啊我不会啊。。。
10min看完题开始码T1T2,没遇到什么障碍30min码完,大数据也过了(其实是目测过的)。。
然后不敢直接写T3,万一T1,T2出事就惨了啊。然后T2默默debug。。
好像没毛病?过!
然而此时已经15:30了。。感觉这速度有点慢了。。
T3,宽搜是肯定的,但是好像有点麻烦啊。
看见旁边2位大佬都打dfs。。。
诶,似乎可以按曼哈顿距离分类建边来spfa。。
但是不连续用膜法怎么处理啊QAQ。。
GDOI的时候也是这类题写spfa就写挂了啊。。
想来想去还是宽搜。。。
思路断断续续,很不清晰。。
怎么记录上一格颜色啊QAQ,多开一维的话好像就爆空间了啊。。(事实是我傻逼用错数组)
16:00了。。。不行不行一定要先写完。。
写到一半发现一个思路?
把白色格子当做一种颜色,走到白色格子花费为2,白色格子走到其他颜色格子花费为1,然后这样类似迷宫问题那样跑?
然后没有证明正确性就开始打了。
调来调去到16:40才过样例。。。大数据没过。。。
于是很快找出了反例。。。这时的心态可能有点崩了吧。。。(1=无望)
想到spfa的话似乎建边直接跑就行了啊,但是不知道自己还能不能调地出来。。T4还没有怎么看呢。。
只剩1h,我还能干什么?
想来想去还是放弃T3,自己写搜索的题真的太弱了,其实实力也不够。。
17:00,开始看T4。。
诶,这个check好像可以n^2的dp啊。。
开始写写写。。。
17:25,写完死活过不了样例。。。感觉是自己方程写错了,毕竟dp一直很差。。
那时头脑确实乱了。。。超级紧张,就是还剩5min数学最后一题还没写出来的那种紧张。。。
退而求其次,dfs!!!
17:30,dfs一直溢出。。。
没办法只能乱调了,然后用不正确的方法乱调过样例。。
17:40,停止码题。。。
查了查文件名和输入输出。。
隐约感觉后2题没分。。。
不想了,好好检查!
于是发现t2,t3都用了y_做变量名,记得曾经某场cf因为这样被卡成CE。。
改改改!!!直接复制到Word里面,Ctrl+F大法好!!!
反复查了几遍,比赛结束。。
走出考场天色已经黑了,心如死灰......
T3他们好像都写出来了呢。T4dp当然也有不少人写出来。
心情也没有和以往一样很不好,毕竟自己实力就这样嘛。。
吃饭的时候仔细回想自己的T4的DP,突然想到没过样例是因为自己默认把第1格当做起点了,还有f数组没有初始化。。。
细节啊!!!如果当时能冷静下来好好在T4 debug就好了,如果T3能冷静下来好好验证正确性就好了。
毕竟已经过去了,就这样吧。
回酒店打了一场Atcoder abc,然后t3都不会写。。信心--,rp--。。
然后颓废了一下,也是忘记几点回房间睡觉了。。
Day 2
回家!!!
然后昏睡一下午。。
晚上作业没心情补。。
总结
1.代码能力太差,一道题往往会调很久,最终无果......
2.写题不能乱写,思路错了还照着写会浪费很多时间,应该做到像LG那样写3题A 3题%%%
3.要敢于尝试,比如T3那样明明思路是对的,但就是太怂不敢写...
4.思想严重江化,定式思维,导致一些题大致思路出来但败在细节...
5.基础还是要巩固吧,毕竟搜索dp都总是写不好呢...
6.心态问题,不要总想着结果,考场上就只有你和题,用心把题写好,把分拿稳就足够了...
7.不能总是停留在想题,要多试着写写,写题速度要加快...
8.一道题调不过的时候要尝试换个思路或者把代码删掉重新写,有时候就是一些错的细节没有改正...
目标&计划
1.今年把两个坑填完...
2.不会的算法就学,然后可以渐渐尝试bzoj,算法要理解不能只是背模版...
3.不要看题解!!!不要看题解!!!不要看题解!!!
最多只能看别人的思路,不能对着别人代码调自己代码!!!
4.锻炼码力,多刷codeforces...希望在这一年能打上蓝名...
洛谷数据测了210,竟然有些心安,只因为T1,T2没炸。。
或许实力太弱只满足于此吧。。
最终也是100+100+10+0,没用的PJ二等滚粗......
初三了...... 有很多想说的话......
初中前2年oi都被自己荒废掉了......很可惜吧......
虽然有想好好努力的觉悟,但始终没有付出足够的时间和精力......
同届的机房oier也基本拿过1=了:qzz,cxk,csl,lg...qzz也是成功ak了呢...
虽然这次也是有一些因为失误考挂的,但他们也都具备了拿1=的实力。。
但感觉自己离1=的实力还是有点远呢......
文化课也是极差......期中裸考已经滚到年级100多......
成功沦为班里oi垫底+文化课垫底......
文化课也是要好好学啊......不能不复习考试啊......
那么,初三就争取把文化课搞好,同时有时间多打比赛多刷题吧......
至于也不要动不动就说要退役,oi的路还很长,不坚持到最后,又怎么知道自己一定做不到呢?
加油qwq......
附:NOIP2017题解
T1
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #include <stack> 7 #include <cmath> 8 using namespace std; 9 int a,b,c; 10 int ans=0; 11 int main() 12 { 13 freopen("score.in","r",stdin); 14 freopen("score.out","w",stdout); 15 scanf("%d%d%d",&a,&b,&c); 16 ans=(a*2+b*3+c*5)/10; 17 printf("%d",ans); 18 fclose(stdin); fclose(stdout); 19 return 0; 20 }
T2
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #include <stack> 7 #include <cmath> 8 using namespace std; 9 int n,q; 10 int a[1050]; 11 int l,num; 12 int ans=0; 13 bool find(int x,int y) 14 { 15 int x2,k=1; 16 x2=x; int c=0; 17 while (x2>0) { 18 c=c+(x2%10)*k; 19 k=k*10; 20 x2=x2/10; 21 if (c==y) return true; 22 if (c>y) return false; 23 } 24 return false; 25 } 26 int main() 27 { 28 freopen("librarian.in","r",stdin); 29 freopen("librarian.out","w",stdout); 30 scanf("%d%d",&n,&q); 31 for (int i=1;i<=n;i++) 32 scanf("%d",&a[i]); 33 sort(a+1,a+n+1); 34 for (int i=1;i<=q;i++) { 35 scanf("%d%d",&l,&num); 36 ans=-1; 37 for (int j=n;j>=1;j--) { 38 if (a[j]<num) continue; 39 if (find(a[j],num)) ans=a[j]; 40 } 41 if (i!=q) printf("%d\n",ans); 42 if (i==q) printf("%d",ans); 43 } 44 fclose(stdin); fclose(stdout); 45 return 0; 46 }
T3
我写了spfa,按曼哈顿距离|x1-x2|+|y1-y2|分类建边;
曼哈顿距离为1,颜色相同边权为0,不同为1...
曼哈顿距离为2,颜色相同边权为2,不同为3...
然后跑一遍裸的spfa... 具体看代码...
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #include <stack> 7 #include <cmath> 8 #define ll long long 9 #define out(a) printf("%d",a) 10 using namespace std; 11 int n,m,fx,fy; 12 int tot=0; 13 bool f=false; 14 int toit[100050],cost[100050],nexts[100050],list[100050],dis[100050],q[100050]; 15 bool flag[100050]; 16 int a[105][105],num[105][105]; 17 int dx[5]={0,0,0,1,-1}; 18 int dy[5]={0,1,-1,0,0}; 19 int read() 20 { 21 int s=0,t=1; char c; 22 while (c<‘0‘||c>‘9‘){if (c==‘-‘) t=-1; c=getchar();} 23 while (c>=‘0‘&&c<=‘9‘){s=s*10+c-‘0‘; c=getchar();} 24 return s*t; 25 } 26 bool check(int x,int y) 27 { 28 if (x<=0||x>m||y<=0||y>m) return false; 29 return true; 30 } 31 void add(int a,int b,int c) 32 { 33 toit[++tot]=b; 34 cost[tot]=c; 35 nexts[tot]=list[a]; 36 list[a]=tot; 37 } 38 void QAQ() 39 { 40 if (a[m-1][m]>0) add(num[m-1][m],num[m][m],2);//,printf("%d %d %d\n",num[m-1][m],num[m][m],2); 41 if (a[m][m-1]>0) add(num[m][m-1],num[m][m],2);//,printf("%d %d %d\n",num[m][m-1],num[m][m],2); 42 if (a[m-1][m-1]>0) add(num[m-1][m-1],num[m][m],3);//,printf("%d %d %d\n",num[m-1][m-1],num[m][m],2); 43 } 44 void spfa(int s) 45 { 46 int v,k,head,tail; 47 head=tail=1; 48 memset(flag,true,sizeof(flag)); 49 memset(dis,127,sizeof(dis)); 50 q[1]=s; flag[s]=false; dis[s]=0; 51 while (head<=tail) { 52 v=q[head]; k=list[v]; 53 while (k!=0) { 54 if (dis[v]+cost[k]<dis[toit[k]]) { 55 dis[toit[k]]=dis[v]+cost[k]; 56 if (flag[toit[k]]) { 57 flag[toit[k]]=false; 58 q[++tail]=toit[k]; 59 } 60 } 61 k=nexts[k]; 62 } 63 flag[v]=true; 64 head++; 65 } 66 } 67 int main() 68 { 69 int x,y,z,xx,yy,xx_,yy_,cnt=0; 70 m=read(); n=read(); 71 for (int i=1;i<=n;i++) { 72 x=read(); y=read(); z=read(); 73 a[x][y]=z+1; 74 } 75 for (int i=1;i<=m;i++) 76 for (int j=1;j<=m;j++) 77 num[i][j]=++cnt; 78 for (int i=1;i<=m;i++){ 79 for (int j=1;j<=m;j++) { 80 if (a[i][j]>0) { 81 for (int k=1;k<=4;k++) { 82 xx=i+dx[k]; yy=j+dy[k]; 83 if (check(xx,yy)) { 84 if (a[xx][yy]>0) { 85 if (a[xx][yy]==a[i][j]) add(num[i][j],num[xx][yy],0);//,printf("%d %d %d\n",num[i][j],num[xx][yy],0); 86 else add(num[i][j],num[xx][yy],1);//,printf("%d %d %d\n",num[i][j],num[xx][yy],1); 87 } 88 else { 89 for (int u=1;u<=4;u++) { 90 xx_=xx+dx[u]; yy_=yy+dy[u]; 91 if (check(xx_,yy_)&&a[xx_][yy_]>0) { 92 if (a[xx_][yy_]==a[i][j]) add(num[i][j],num[xx_][yy_],2);//,printf("%d %d %d\n",num[i][j],num[xx_][yy_],2); 93 else add(num[i][j],num[xx_][yy_],3);//,printf("%d %d %d\n",num[i][j],num[xx_][yy_],3); 94 } 95 } 96 } 97 } 98 } 99 } 100 } 101 } 102 if (a[m][m]==0) QAQ(); 103 spfa(1); 104 if (dis[m*m]==2139062143) out(-1); 105 else out(dis[m*m]); 106 }
T4
正解是二分+DP+单调队列优化...
由于自己不会单队优化看了很多篇博客和题解才大概会写...
f[i]=max(f[i],f[j]+s[i]);
f[j]是随i的右移而右移的,会重复枚举很多个f[j],所以可以用单调队列存下f[j]...
所以我们只要找的是max(f[j])...
对于格子j,如果j到i的距离>最大距离,就可以直接把它出队...
对于格子j,如果j到i的距离>=最小距离,把f[j]与队尾比较,如果f[q[tail]]<f[j],那么f[q[tail]]也是可以直接出队...
因此维护的是一个单调递减队列,队头就是最大值就可以直接用...
记得判head<=tail,记得开ll!!!
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #include <stack> 7 #include <cmath> 8 #define ll long long 9 #define out(a) printf("%d",a) 10 using namespace std; 11 int n,d,k; 12 int x[500050],s[500050]; 13 ll f[500050]; 14 ll q[500050]; 15 ll lbound,rbound,middle; 16 ll sum=0; 17 int read() 18 { 19 int s=0,t=1; char c; 20 while (c<‘0‘||c>‘9‘){if (c==‘-‘) t=-1; c=getchar();} 21 while (c>=‘0‘&&c<=‘9‘){s=s*10+c-‘0‘; c=getchar();} 22 return s*t; 23 } 24 ll getmin(ll x) 25 { 26 if (x>=d) return 1; 27 return d-x; 28 } 29 ll getmax(ll x) 30 { 31 return x+d; 32 } 33 ll check(ll m) 34 { 35 ll maxn=(ll)-1<<60; 36 int head,tail; 37 head=1; tail=0; 38 int now=0; 39 for (int i=1;i<=n;i++) 40 f[i]=(ll)-1<<60; 41 f[0]=0; 42 for (int i=1;i<=n;i++) { 43 while (x[now]+getmin(m)<=x[i]) { 44 while (head<=tail&&f[now]>f[q[tail]]) tail--; 45 q[++tail]=now; 46 now++; 47 } 48 while (head<=tail&&x[q[head]]+getmax(m)<x[i]) head++; 49 if (head<=tail) f[i]=f[q[head]]+s[i]; 50 } 51 for (int i=0;i<=n;i++) 52 maxn=max(maxn,f[i]); 53 return maxn; 54 } 55 int main() 56 { 57 n=read(); d=read(); k=read(); 58 for (int i=1;i<=n;i++) { 59 x[i]=read(),s[i]=read(); 60 if (s[i]>0) sum=sum+s[i]; 61 } 62 lbound=1; rbound=x[n]; 63 if (sum<k) { 64 puts("-1"); 65 return 0; 66 } 67 while (lbound<=rbound) { 68 middle=(lbound+rbound)>>1; 69 if (check(middle)>=k) rbound=middle-1; 70 else lbound=middle+1; 71 //printf("%d %d\n",middle,check(middle)); 72 } 73 out(lbound); 74 return 0; 75 }
以上是关于NOIP2017的主要内容,如果未能解决你的问题,请参考以下文章