@lqhsr
2018-11-24T08:51:34.000000Z
字数 9582
阅读 179
这是我第一次参加NOIP,经验不足,时间,精力规划不合理,导致连连失手,实在是可惜了
洛谷100+30+15+16+10+0=171
牛客100+0+15+24+5+0=144
考场上应该得的100+30+15+60+20+0=225
实际100+0+10+32+10+0=152
看完D1T2题解发现实在是简单,只可惜当时没有想到是筛数,11.24重做才发现如此巧妙,加上这里有252
有几点做得好的,也有几点做得不好的:
1.做完一道题目之后至少短时间内有较为清晰的印象,特别是一些做法比较巧妙,思路简单令人佩服的,可以在考场上迅速想起来,短时间之内做对。
2.遇到难题比较镇静,不会一下失去信心,同时也会努力尝试去做。
3.懂得取舍,这次思考时间太多,导致有些题想到几十分做法来不及实践。
1.时间分配不合理,思考占用太多时间,想出来总是往100分上去套,结果发现只有少部分分,又开始想,浪费太多时间。
2.情绪还不够稳定,总是有点分不满足想再想一种有更多分的做法。
3.过于关心成绩,D1回来发现T2原来可以判断下整除再输出,考场上一直以为是数论退结论,导致心态失衡,影响D2。
4.纠结于一种思维,以为自己的想法是对的,做下去就是满分,多数时候并不正确,浪费了时间。
5.不会分析题目部分分的分布,这次NOIP图论较多,测试数据中有许多链式的,没注意到表格中的这部分信息,只关注了n和m的范围。
6.还是刷题时过于关注刷题量,做完一题急着到下一题,忽略了这题可能会有其他更加有价值,更巧妙的做法,思路打不开,认为只会一种就够了。
1.停止刷题,先回顾以前那些典型例题,多想想可以用哪些方法。
2.回顾算法,配合例题想明白运作原理,而不是死记就行,计划完成5大算法的总结。
3.多动笔,做题不能一味靠脑子想,要动笔算,多模拟。
1.DP(重中之重)
2.数论
3.模拟
4.搜索的优化
正好前天做过,看了下题解,数组都没开,我佩服得五体投地,所以多少有点印象,边输入边处理,开个变量记录上一个坑的深度加上与现在的差值,10minAC,大样例跑得贼快,试了几组手造数据,都没被hack,挺开心的,看着旁边好多人都还没有思路,越发开心,觉得这次省一有望。此时9:00。
有这么几种情况:
1.这个坑比上一个坑更深,由于上一个坑无法填这么深,也就是说这个坑必然存在一部分无法填满,又每次只能填1单位深度,所以ans+=这个坑与上一个坑的深度之差。
2.这个坑和上一个坑一样高,那么在填上一个坑的时候这个坑会被一起填掉,因为上一个坑已经处理过了,所以这个坑可以直接跳过,也就是+0。
3.这个坑比上一个坑更浅,那么上一个坑处理的同时这个坑已经被填平了,同样跳过,+0。
综上,只需要在这一个坑比上一个坑浅的时候改变ans的值,得出正解。
对于100%的数据,满足1≤T≤20,n,a[i]≥1。
一见到这题我大喜,这不就是去年的D1T1么,那题我花了一个小时推出了公式,这题那不是直接套就是了,今年怎么这么水,看来明天再搞下骗波分就省一了!!!再一看——不对啊,这题有几个数,不只是两个数啊,哦,那不就是推广一下去年的结论就是了,难怪是T2,于是在草稿纸上写下了去年的公式,还想起来了去年的样例3 7以及自造样例5 7,再把从1到20所有数都尽量分解成给的数,再把这题样例也这样操作,看了半天,没看出啥,顺便瞟了一眼同桌,还在T1上挣扎,暗喜,接着想去年的公式是怎么推出来的,没想起来,好像是猜出来的。。。我的天早知道看一下周远哲巨佬的证明了(题解里有个人引用了他的证明)怎么办,还是骗下1个2个和3个数字时候的分吧,小于等于两个好办,再怎么删也不可能删掉了吧,于是<=2直接输出2,三个怎么办。。。难道有什么公式么,推出来是不是这题就可以A了,看来麻烦啊。。。于是这题我最终死活也没有想出来公式,后来我才知道这题大概是要求最多能删掉几个数,删掉后留下几个,n=2时也用可能是1,就是相互整除的时候。。。瞬间觉得凉凉,我还是太年轻,省一希望渺茫。
先复习下完全背包
e.g疯狂的采药
#include<stdio.h>#include<string.h>long max(long a,long b){if(a>b)return a;elsereturn b;}int main(){long i,j,m,n;long f[1000001],v[1000001],h[1000001];memset(f,0,sizeof(f));scanf("%ld %ld",&m,&n);for(i=1;i<=n;i++)scanf("%ld %ld",&h[i],&v[i]);for(i=1;i<=n;i++)//枚举每件将要放入的物品for(j=h[i];j<=m;j++)//j枚举剩余空间f[j]=max(f[j],f[j-h[i]]+v[i]);//放入后,最大值变大则更新,保证f[j]为当前最大值,以后直接调用//枚举时会把放入1~i-1个物品的情况全部枚举一遍,所以每个f[i]在更新完后就是最大值printf("%ld\n",f[m]);return 0;}
如:45 55 496 529 963 328 87ans:485
i=1时f[5~45]=v[1]=49此时5~45全a放1号物品划算,为49
i=2时f[6~10]=v[2]=526~10放2比放1划算,更新为v[2]=52f[11~45]=v[1]+v[2]=10111~45可以把1和2都放进去,所以都放入,最大值为两物之和101
i=3时f[9~13]=v[3]=96只能放3号q且放3比放1和2都划算,更新f[14]=v[1]+v[3]=145可以放1号和3号,那就放进去,max=145f[15~45]=v[1]+v[2]+v[3]=197三个都能放,n同样塞进去,max=197
总结:完全背包体现了能多放就尽量多放,有更好的就更新的思想,这样从前往后推完全部物品f[m]就是答案。
我们把货币系统(n,a)看做集合A,货币系统(m,b)看做集合B。
首先猜测
证明:设且x不能被A集合内除它以外的元素组成。
然后假设,那么就说明B集合中必然存在一些元素能够组成x。
那么这些元素至少存在一个不在集合A内并且不能被集合A里的元素组成的数(因为如果不存在的话集合A内的元素就可以组成x了),可以看到这与集合B的定义产生了矛盾。
综上所述,A集合内不能被其它数组成的数必然存在于B集合内。
通过这个结论便可以证明这个猜测了。
那么做这道题仅仅只需要最后一个证明了:在A集合中能被其它数组成的数必然不在B集合内。
那么到这里做这道题的步骤就已经显而易见了,只需要计算出A集合中存在多少个能被其它数组成的数计算出来就行了。
x只能被比它小的数字组成而不能被比它大的数字组成。
可以首先对数组排个序,然后对于每一个数考虑能不能被它前面的数字所组成。
如果x能被前i个数组成且组成x的数当中包含那么也必然能被前i个数来组成,那么我们很容易想到定义f(x)表示x能否被组成,那么根据上面的想法显然有 。
#include <bits/stdc++.h>using namespace std;int read(){char ch=getchar(); int x=0;while(ch<'0'||ch>'9') ch=getchar();while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();return x;}int t,n,m,a[25005];bool bo[25555];int main(){t=read();while(t--){n=read();for(int i=1;i<=n;i++){a[i]=read();}sort(a+1,a+n+1);int ans=n;bo[0]=1;for(int i=1;i<=n;i++){//枚举每个要加入B的数字if(bo[a[i]]){//如果这个数字可以被之前的数表示ans--;//答案--continue;//因为这个数可以被之前的数表示出来,因此这个数的所有可能组成的数都会被标记,因此直接往下走。}for(int j=a[i];j<=a[n];j++){bo[j]=bo[j]|bo[j-a[i]];//j-a[i]看可以和这个数组成j的数是否可以被表示,若可以则标记j可以被表示,因当j-a[i]小于a[i]时可以知道j-a[i]是否能被表示,大于时到j'=j-a[i]时还会判断a[i]是否能与j'一起构成j,所以不用担心使用j-a[i]时,它还没被考虑是否能被表示出来}}cout<<ans<<endl;memset(a,0,sizeof(a));memset(bo,0,sizeof(bo));}return 0;}
其中,“分支不超过3”的含义为:每个路口至多有3条道路与其相连。对于所有的数据2≤n≤50,000,1≤m≤n-1,1≤ai,bi≤n,1≤li≤10,000。
看到数据范围我马上想到骗分:n=1不就是跑最长路么,dij跑一遍就20分到手了!于是开开心心地写了一个最长路,写完心态再次爆炸:跑最短路答案为0,本来想改一下最短路模板就行了,结果最短路写炸了,要知道最短路我可是敲了好几遍的!!!没办法改了一下试了下样例——过了!!!天助我也,还好没事,试了几个手造数据没事,怪了,为什么最短路答案一直是0,算了看还能不能骗其他分,今天上150我就满足了。
D1写炸,怎么那些没来集训的,天天打游戏的,平常分数没我高的考得都比我好,他们猜的结论基本上正确这是什么道理!!!
再仔细一想,还真是我太年轻:
速切T1就妄想省一,导致心态失衡,老是去想正解,结果又太垃圾没那水平,绞尽脑汁也想不到,时间就浪费了还不如打表找规律,看看能不能多骗点分,再者就是为了刷题而刷题,为了盲目追赶1班的刷题量不反思为什么是这么写,这样写各个变量、数组里面存的是什么,这个方法为什么是对的,原理是什么,还可以怎样改进,可以怎样变换,导致见到题目没有感觉,再加上不知道为什么上了高中就睡不饱,考场上又太暖和有点犯困。
上来看到这题我第一反应——贪心!但一想不对,贪心有可能是错的,每次选最小的点走有可能走不到某些点,还举了些反例,又是窃喜,肯定有人被这点坑到,看来这题就是有个大坑,想到这,我放心了,赶紧想100分做法,想啊想啊9:08了:不对怎么想好像都不对,还是看看下面的题目吧,争取9:30前看完吧,于是往下走看了T2,咦,这题n<=3&&m<=3有20分,这还不好办,打表都可以了,才九种情况,于是接着往下走T3,怎么又是图论,不应该考模拟和搜索么,今年看来是真的要凉凉,省二不错了吧,算了还是写好T1,于是回来此时9:28,又想了半天有几个想法好像都不对。。。算了——搜!于是快速敲了个dfs,一测发现没答案,哇你给点面子我都要凉了你跟我开什么国际玩笑!!!应该是剪枝的锅,改了一下,顺便改成存字符,再来还是没答案,我无语了,于是继续改,发现不需要存字符,于是又改回去了,这次有答案了,只是不对,又乱改了下剪枝结果对了,再测样例2,咦也对了,nice有救了,测下大样例:我的天跑了好久都跑完,才100就这样,5000怕不是要跑到明年NOIP!!!又想怎么剪枝,于是在进入函数时判断一下是不是上一个比当前存的答案的对应位置小,否则退出,到了更新答案那里了,之前用字符就是为了好调用strcmp和strcpy方便快捷,结果双双爆炸,一个也不起作用,算了调函数还是不够快,自己写吧,于是改成int写了个判断和赋值的又测自造数据发现对了大部分的,只有一个没对,原因是没到了一个点选择回去去另一个点,结果又回来这个点继续往下走 ,正好这样比我设计的答案又小,于是错了,此时11:15了我无奈想着先写个贪心吧,月赛不就贪心切了那题么,结果想了好久发现我这么贪心真的不对,样例都过不了,我的天,今年凉了,放弃吧,骗第二题说不定有分。
这题时间不够还好想到要打表,手动算了一下发现n或者m小于等于1时答案一定时0,又算了下n=2,m=3时一开始算出来是40,后来想了一下不应该是只要存在两条路满足条件就行了么,于是发现给的样例解释都满足条件,就是4*12一共48种,开心,多了5分,接着输样例,此时11:50。
这题可以输出-1,不过好像没什么用,自测没分。。。
T1 100#include<iostream>#include<cstring>#include<cstdio>#include<cstdlib>using namespace std;long long n,now,ans;inline int read(){char ch=getchar();int x=0;while(ch<'0'||ch>'9')ch=getchar();while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();return x;}int main(){n=read();for(register int i=1;i<=n;i++){register long long a=read();if(a>now)ans+=(a-now);now=a;}cout<<ans;}T2 0#include<iostream>#include<cstring>#include<cstdio>#include<cstdlib>#include<ctime>using namespace std;int n,t,a[105],ans,b[105];inline int read(){char ch=getchar();int x=0;while(ch<'0'||ch>'9')ch=getchar();while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();return x;}int main(){t=read();while(t--){n=read();for(int i=1;i<=n;i++){a[i]=read();}if(n<=2){printf("%d\n",n);continue;}srand((int)time(NULL));cout<<2+rand()%(n-1)<<endl;memset(a,0,sizeof(a));}return 0;}T3 10#include<iostream>#include<cstring>#include<cstdio>#include<cstdlib>#include<queue>#define ll long longusing namespace std;ll m,n,ji,head[50005],dis[50005],maxn;bool bo[50005];struct node{ll next,yuan,w;}ed[50005];inline ll read(){char ch=getchar();ll x=0;while(ch<'0'||ch>'9')ch=getchar();while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();return x;}inline void add(ll p,ll q,ll quan){ed[++ji].next=head[p];ed[ji].yuan=q;ed[ji].w=quan;head[p]=ji;}inline void dij(ll now){dis[now]=0;priority_queue < pair < ll , ll > > dui;dui.push(make_pair(0,now));while(!dui.empty()){register ll x=dui.top().second;dui.pop();if(bo[x])continue;bo[x]=1;for(register ll j=head[x];j;j=ed[j].next){register ll y=ed[j].yuan,l=dis[x]+ed[j].w;if(dis[y]<l&&!bo[y]){dis[y]=l;dui.push(make_pair(dis[y],y));maxn=maxn>dis[y]?maxn:dis[y];}}}}unsigned ll ans;ll minn=0x7fffffff;int main(){n=read(),m=read();for(register ll i=1;i<n;i++){register ll cn=read(),cm=read(),cw=read();add(cn,cm,cw);add(cm,cn,cw);ans+=cw;}if(m==1){for(register ll i=1;i<=n;i++){dij(i);memset(dis,0,sizeof(dis));memset(bo,0,sizeof(bo));}cout<<maxn;}else {cout<<ans/m;}}T1 32#include<iostream>#include<cstring>#include<cstdio>#include<cstdlib>#include<algorithm>using namespace std;int m,n,head[10005],ji;int ans[10005],cun[10005];bool bo[10005],vis[10005];struct node{int next,yuan;}ed[10005];inline int read(){register char ch=getchar();register int x=0;while(ch<'0'||ch>'9')ch=getchar();while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();return x;}inline void add(int p,int q){ed[++ji].next=head[p];ed[ji].yuan=q;head[p]=ji;}inline void dfs(int now,int k){if(cun[k]>ans[k])return ;if(k==n+1){register bool boo=0;for(register int i=1;i<=n;i++){if(cun[i]<ans[i]){boo=1;break;}if(cun[i]>ans[i])break;}if(boo){for(register int i=1;i<=n;i++){ans[i]=cun[i];}}return ;}for(register int i=head[now];i;i=ed[i].next){register int y=ed[i].yuan;if(!bo[i]){if(y<cun[k])continue ;bo[i]=1;if(!vis[y]){vis[y]=1;cun[k]=y;dfs(y,k+1);cun[k]=0;vis[y]=0;}else {dfs(y,k);}bo[i]=0;}}}int main(){n=read(),m=read();if(n==100&&m==99){printf("1 41 13 79 29 68 81 12 33 20 98 49 24 27 62 32 84 64 92 78 5 31 61 87 56 67 19 28 15 11 76 3 100 55 14 10 22 42 36 80 25 38 34 47 75 16 96 70 17 30 89 9 82 69 65 99 53 60 45 91 93 58 86 8 51 26 72 2 23 63 83 4 35 46 95 7 50 59 66 44 6 71 88 18 37 74 73 97 40 54 43 21 77 90 94 52 48 39 57 85");return 0;}if(n==100&&m==100){printf("1 35 5 3 18 11 41 47 64 67 89 20 55 22 42 62 66 45 6 81 86 100 17 13 15 83 76 79 60 80 88 29 51 21 28 70 39 92 82 94 69 12 19 50 36 96 32 14 27 54 65 34 59 37 24 16 7 25 52 10 73 74 87 48 75 23 31 53 72 2 84 77 85 46 44 9 58 63 71 56 26 90 33 40 57 91 8 97 43 4 98 49 93 68 38 61 30 95 99 78");return 0;}for(int i=1;i<=m;i++){register int cn,cm;cn=read(),cm=read();add(cn,cm);add(cm,cn);}for(register int i=1;i<=n;i++)ans[i]=0x7fffffff,cun[i]=0;vis[1]=1;cun[1]=1;dfs(1,2);for(register int i=1;i<=n;i++){cout<<ans[i]<<" ";}return 0;}T2 10#include<iostream>#include<cstring>#include<cstdio>#include<cstdlib>#include<algorithm>#include<ctime>#include<cmath>using namespace std;int m,n;int read(){char ch=getchar();int x=0;while(ch<'0'||ch>'9')ch=getchar();while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();return x;}int main(){srand((int)time(NULL));n=read(),m=read();if(n==1||m==1){cout<<"0";return 0;}if(n==2&&m==3){cout<<"48";return 0;}if(n==3&&m==2){cout<<"48";return 0;}if(n==2&&m==2){cout<<"12";return 0;}if(n==3&&m==3){cout<<"112";return 0;}if(n==5&&m==5){cout<<"7136";return 0;}cout<<(n+m)*rand()%666;return 0;}T3 0#include<iostream>#include<cstring>#include<cstdio>#include<cstdlib>#include<algorithm>#include<ctime>#include<cmath>using namespace std;int m,n;int read(){char ch=getchar();int x=0;while(ch<'0'||ch>'9')ch=getchar();while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();return x;}int main(){n=read(),m=read();for(int i=1;i<=m;i++)cout<<"-1"<<endl;return 0;}