NOIP2017模拟赛(十四)总结
来源:互联网 发布:淘宝体检中心进不去 编辑:程序博客网 时间:2024/05/29 10:21
由于特殊原因,从接下来开始NOIP2017模拟赛的总结将不再显示题面。这意味着可能只有队友和老师能够看到总结内容的全部,不便之处敬请原谅。
T1:最大得分(SMOJ1964)
题目分析:这题看上去没那么容易,但仔细想想还是挺简单的。首先发现答案不可能超过7,于是我们就枚举答案。假设原串长度为12,枚举答案为2,则原串可以抽象成下面的样子:
1 2 3 3 2 1 1 2 3 3 2 1
其中标相同数字的地方最后要变成相同字母。接下来就是个很显然的贪心了。假设’a’在四个1的地方出现次数最多,那就把他们都变成’a’,并计算代价……。最后用总代价和maxChanges比较即可。其实这题还可以二分答案,不过我认为没有必要。
CODE:
#include<iostream>#include<string>#include<cstring>#include<cmath>#include<cstdio>#include<cstdlib>#include<stdio.h>#include<algorithm>using namespace std;const int maxl=55;const int maxc=30;int cnt[maxc];int id[maxl][maxl];int cur;char s[maxl];int a[maxl];int c;int Get(){ int temp=0; for (int i=1; i<=cur; i++) { memset(cnt,0,sizeof(cnt)); int num=id[i][0]; for (int j=1; j<=num; j++) cnt[ a[ id[i][j] ] ]++; int k=num; for (int j=0; j<maxc; j++) k=min(k,num-cnt[j]); temp+=k; } return temp;}int main(){ freopen("1964.in","r",stdin); freopen("1964.out","w",stdout); scanf("%s",&s); scanf("%d",&c); int slen=strlen(s); for (int i=0; i<slen; i++) a[i+1]=s[i]-'a'; int max_ans=1,temp=slen; while ( !(temp&1) ) max_ans++,temp>>=1; int T=slen/temp; cur=(temp+1)>>1; for (int i=0; i<T; i++) { int h=i*temp; int j; for (j=1; (j<<1)<=temp; j++) { id[j][ ++id[j][0] ]=h+j; id[j][ ++id[j][0] ]=h+temp-j+1; } id[j][ ++id[j][0] ]=h+j; } if ( Get()<=c ) { printf("%d\n",max_ans); return 0; } for (int i=max_ans-1; i>=1; i--) { cur=slen>>i; temp=cur<<1; T=slen/temp; memset(id,0,sizeof(id)); for (int j=0; j<T; j++) { int h=j*temp; int k; for (k=1; (k<<1)<=temp; k++) { id[k][ ++id[k][0] ]=h+k; id[k][ ++id[k][0] ]=h+temp-k+1; } } if ( Get()<=c ) { printf("%d\n",i); return 0; } } printf("0\n"); return 0;}
T2:寄存器(SMOJ1965)
题目分析:对于这种看上去很玄学的题目,我们一般要分析出一些特征和性质,才能使问题简单化。①这题首先有一个结论:如果我已经知道了最后的X和Y,我是可以倒推出操作序列的。如果X>Y,上一步的两个数一定是X-Y和Y。②从上面的结论我们也可以看出,最后的X和Y必定互质,否则在倒推的过程中就会出现X=Y且X,Y都不为1的情况,这和题意不符。③当然还有一个小结论:最后的Y一定小于X(这不是废话吗)。
那么我们枚举Y,然后用类似求Gcd的方法计算出从(1,1)到(X,Y)所需要的步数。由于Gcd是log( log(n) )的,可以证明做这一步的时间接近线性(事实上我考试的时候还在担心会不会超时来着)。然后就是要处理字典序问题。如果我们在做上面这一步的时候一边Gcd一边生成字典序,肯定超时。我们不妨先将最少步数step求出来,并用一个数组记录需要操作step步的那些Y值。直觉告诉我最后的step值不会很大,那些Y的个数也不会很多(事实上X=
CODE:
#include<iostream>#include<string>#include<cstring>#include<cmath>#include<cstdio>#include<cstdlib>#include<stdio.h>#include<algorithm>using namespace std;const int maxn=100000;int num[maxn];int val,cur;int ans[maxn];int temp[maxn];int len;int G,R;int now;int Gcd(int x,int y){ if (!y) return x; return Gcd(y,x%y);}int Get(int x,int y){ if (!y) return -1; return x/y+Get(y,x%y);}void Work(int x,int y){ if (!y) return; while (x>=y) x-=y,temp[++len]=now; now=1-now; Work(y,x);}void Check(){ for (int i=1; i<=val; i++) { if (temp[i]<ans[i]) break; if (ans[i]<temp[i]) return; } for (int i=1; i<=val; i++) ans[i]=temp[i];}int main(){ freopen("1965.in","r",stdin); freopen("1965.out","w",stdout); scanf("%d",&G); while (G--) { scanf("%d",&R); val=R-1; cur=1; num[1]=1; for (int i=2; i<R; i++) if ( Gcd(R,i)==1 ) { int v=Get(R,i); if (v==val) num[++cur]=i; else if (v<val) val=v,cur=1,num[1]=i; } for (int i=1; i<=val; i++) ans[i]=1; for (int i=1; i<=cur; i++) { len=now=0; Work(R,num[i]); for (int j=1; (j<<1)<=val; j++) swap(temp[j],temp[val-j+1]); Check(); } for (int i=1; i<=val; i++) printf("%c",'X'+ans[i]); printf("\n"); } return 0;}
T3:肯德基(SMOJ1966)
题目分析:我比赛的时候写了个
我们分析一下就能得到一个结论:如果我们要从第
如果这一个部分直接用多源最短路算法做,我们就要对原图重新建边。将原图中最左边一排的格子标号为1~r,最右边的一排格子标号为r+1~2r,然后在
后来我回家考虑了一下,新图的边数只有6r,如果我用
老师说100分要用DP,然而我不知道要按什么顺序去做,想了好久都想不出来。直到kekxy神犇告诉我他是用DP的……这题的难点在于某两个点之间的最短路可能是蛇形的:
但有一个性质:从
那我们不妨枚举
(注意,以上三条路径在省略号处可能是很曲折的)
到达
CODE(Dijkstra+Heap):
#include<iostream>#include<string>#include<cstring>#include<cmath>#include<cstdio>#include<cstdlib>#include<stdio.h>#include<algorithm>using namespace std;const int maxr=2010;const int maxc=210;const int oo=1000000001;struct edge{ int obj,len; edge *Next;} e[maxr*6];edge *head[maxr<<1];int cur=-1;int Heap[maxr<<1];int id[maxr<<1];int tail,s;int dis[maxr<<1][maxr<<1];int lsum[maxr];int rsum[maxr];int hsum[maxr][maxc];int t[maxr][maxc];int r,c,d;int Min(int x,int y){ if (x<y) return x; return y;} int Get(int lx,int ly,int nx,int ny){ int temp=oo,k=oo; if (lx==nx) { k=-t[lx][ly]; k+=(hsum[nx][ max(ly,ny) ]-hsum[lx][ min(ly,ny)-1 ]); } int lleft=hsum[lx][ly]-t[lx][1],lright=hsum[lx][c]-hsum[lx][ly-1]-t[lx][c]; int nleft=hsum[nx][ny]-t[nx][1],nright=hsum[nx][c]-hsum[nx][ny-1]-t[nx][c]; temp=Min(temp, lleft+dis[lx][nx]+nleft ); temp=Min(temp, lright+dis[r+lx][r+nx]+nright ); temp=Min(temp, lleft+dis[lx][r+nx]+nright ); temp=Min(temp, lright+dis[r+lx][nx]+nleft ); return Min(temp-t[lx][ly],k);}void Preparation(){ lsum[1]=t[1][1]; rsum[1]=t[1][c]; for (int i=2; i<=r; i++) { lsum[i]=lsum[i-1]+t[i][1]; rsum[i]=rsum[i-1]+t[i][c]; } for (int i=1; i<=r; i++) { hsum[i][1]=t[i][1]; for (int j=2; j<=c; j++) hsum[i][j]=hsum[i][j-1]+t[i][j]; }}void Add(int x,int y,int z){ cur++; e[cur].obj=y; e[cur].len=z; e[cur].Next=head[x]; head[x]=e+cur;}void Add_edge(){ for (int i=1; i<=(r<<1); i++) head[i]=NULL; for (int i=1; i<r; i++) { Add(i,i+1,t[i+1][1]); Add(i+1,i,t[i][1]); Add(r+i,r+i+1,t[i+1][c]); Add(r+i+1,r+i,t[i][c]); } for (int i=1; i<=r; i++) { Add(i,r+i,hsum[i][c]-t[i][1]); Add(r+i,i,hsum[i][c-1]); }}void Swap(int &x,int &y){ int z=x; x=y; y=z;}int Get(){ int temp=Heap[1]; Heap[1]=Heap[tail]; id[ Heap[1] ]=1; tail--; int x=1; while (1) { int y=x,Left=x<<1,Right=Left|1; if ( Left<=tail && dis[s][ Heap[Left] ]<dis[s][ Heap[y] ] ) y=Left; if ( Right<=tail && dis[s][ Heap[Right] ]<dis[s][ Heap[y] ] ) y=Right; if (y==x) break; Swap(Heap[x],Heap[y]); Swap(id[ Heap[x] ],id[ Heap[y] ]); x=y; } return temp;}void Update(int x){ while (x>1) { int y=x>>1; if (dis[s][ Heap[y] ]<=dis[s][ Heap[x] ]) break; Swap(Heap[x],Heap[y]); Swap(id[ Heap[x] ],id[ Heap[y] ]); x=y; }}void Release(int x,int y,int l){ if (dis[s][x]+l>=dis[s][y]) return; dis[s][y]=dis[s][x]+l; Update(id[y]);}void Dijkstra(int x){ s=x; for (int i=1; i<=(r<<1); i++) dis[s][i]=oo; dis[s][s]=0; tail=1; Heap[1]=s; for (int i=1; i<=(r<<1); i++) if (i!=s) Heap[++tail]=i,id[i]=tail; for (int i=1; i<(r<<1); i++) { x=Get(); for (edge *p=head[x]; p; p=p->Next) Release(x,p->obj,p->len); }}int main(){ freopen("1966.in","r",stdin); freopen("1966.out","w",stdout); scanf("%d%d",&r,&c); for (int i=1; i<=r; i++) for (int j=1; j<=c; j++) scanf("%d",&t[i][j]); Preparation(); Add_edge(); for (int i=1; i<=(r<<1); i++) Dijkstra(i); for (int i=1; i<=r; i++) for (int j=1; j<=(r<<1); j++) { dis[i][j]+=t[i][1]; dis[r+i][j]+=t[i][c]; } scanf("%d",&d); long long ans=t[1][1]; int lx=1,ly=1; for (int i=1; i<=d; i++) { int x,y; scanf("%d%d",&x,&y); ans+=Get(lx,ly,x,y); lx=x; ly=y; } printf("%lld\n",ans); return 0;}
CODE(SPFA):
#include<iostream>#include<string>#include<cstring>#include<cmath>#include<cstdio>#include<cstdlib>#include<stdio.h>#include<algorithm>using namespace std;const int maxr=2010;const int maxc=210;const int oo=2000000001;struct edge{ int obj,len; edge *Next;} e[maxr*6];edge *head[maxr<<1];int cur=-1;bool vis[maxr<<1];int que[maxr<<1];int he,ta;int dis[maxr<<1][maxr<<1];int lsum[maxr];int rsum[maxr];int hsum[maxr][maxc];int t[maxr][maxc];int r,c,d;int Min(int x,int y){ if (x<y) return x; return y;} int Get(int lx,int ly,int nx,int ny){ int temp=oo,k=oo; if (lx==nx) { k=-t[lx][ly]; k+=(hsum[nx][ max(ly,ny) ]-hsum[lx][ Min(ly,ny)-1 ]); } int lleft=hsum[lx][ly]-t[lx][1],lright=hsum[lx][c]-hsum[lx][ly-1]-t[lx][c]; int nleft=hsum[nx][ny]-t[nx][1],nright=hsum[nx][c]-hsum[nx][ny-1]-t[nx][c]; temp=Min(temp, lleft+dis[lx][nx]+nleft ); temp=Min(temp, lright+dis[r+lx][r+nx]+nright ); temp=Min(temp, lleft+dis[lx][r+nx]+nright ); temp=Min(temp, lright+dis[r+lx][nx]+nleft ); return Min(temp-t[lx][ly],k);}void Preparation(){ lsum[1]=t[1][1]; rsum[1]=t[1][c]; for (int i=2; i<=r; i++) { lsum[i]=lsum[i-1]+t[i][1]; rsum[i]=rsum[i-1]+t[i][c]; } for (int i=1; i<=r; i++) { hsum[i][1]=t[i][1]; for (int j=2; j<=c; j++) hsum[i][j]=hsum[i][j-1]+t[i][j]; }}void Add(int x,int y,int z){ cur++; e[cur].obj=y; e[cur].len=z; e[cur].Next=head[x]; head[x]=e+cur;}void Add_edge(){ for (int i=1; i<=(r<<1); i++) head[i]=NULL; for (int i=1; i<r; i++) { Add(i,i+1,t[i+1][1]); Add(i+1,i,t[i][1]); Add(r+i,r+i+1,t[i+1][c]); Add(r+i+1,r+i,t[i][c]); } for (int i=1; i<=r; i++) { Add(i,r+i,hsum[i][c]-t[i][1]); Add(r+i,i,hsum[i][c-1]); }}void Swap(int &x,int &y){ int z=x; x=y; y=z;}void SPFA(int s){ for (int i=1; i<=(r<<1); i++) dis[s][i]=oo,vis[i]=false; dis[s][s]=0,vis[s]=true; he=0,ta=1,que[1]=s; while (he!=ta) { he=(he+1)%(maxr<<1); int node=que[he]; for (edge *p=head[node]; p; p=p->Next) { int son=p->obj; if (dis[s][node]+p->len<dis[s][son]) { dis[s][son]=dis[s][node]+p->len; if (!vis[son]) { vis[son]=true; ta=(ta+1)%(maxr<<1); que[ta]=son; } } } vis[node]=false; int nhe=(he+1)%(maxr<<1); if (dis[s][ que[ta] ]<dis[s][ que[nhe] ]) Swap(que[ta],que[nhe]); }}int main(){ freopen("1966.in","r",stdin); freopen("1966.out","w",stdout); scanf("%d%d",&r,&c); for (int i=1; i<=r; i++) for (int j=1; j<=c; j++) scanf("%d",&t[i][j]); Preparation(); Add_edge(); for (int i=1; i<=(r<<1); i++) SPFA(i); for (int i=1; i<=r; i++) for (int j=1; j<=(r<<1); j++) { dis[i][j]+=t[i][1]; dis[r+i][j]+=t[i][c]; } scanf("%d",&d); long long ans=t[1][1],lx=1,ly=1; for (int i=1; i<=d; i++) { int x,y; scanf("%d%d",&x,&y); ans+=Get(lx,ly,x,y); lx=x; ly=y; } printf("%lld\n",ans); return 0;}
CODE(DP):
#include<iostream>#include<string>#include<cstring>#include<cmath>#include<cstdio>#include<cstdlib>#include<stdio.h>#include<algorithm>using namespace std;const int maxr=2010;const int maxc=210;const int oo=1000000001;int dis[maxr<<1][maxr<<1];int lsum[maxr];int rsum[maxr];int hsum[maxr][maxc];int t[maxr][maxc];int r,c,d;int Min(int x,int y){ if (x<y) return x; return y;}int Get(int lx,int ly,int nx,int ny){ int temp=oo,k=oo; if (lx==nx) { k=-t[lx][ly]; k+=(hsum[nx][ max(ly,ny) ]-hsum[lx][ Min(ly,ny)-1 ]); } int lleft=hsum[lx][ly]-t[lx][1],lright=hsum[lx][c]-hsum[lx][ly-1]-t[lx][c]; int nleft=hsum[nx][ny]-t[nx][1],nright=hsum[nx][c]-hsum[nx][ny-1]-t[nx][c]; temp=Min(temp, lleft+dis[lx][nx]+nleft ); temp=Min(temp, lright+dis[r+lx][r+nx]+nright ); temp=Min(temp, lleft+dis[lx][r+nx]+nright ); temp=Min(temp, lright+dis[r+lx][nx]+nleft ); return Min(temp-t[lx][ly],k);}void Preparation(){ lsum[1]=t[1][1]; rsum[1]=t[1][c]; for (int i=2; i<=r; i++) { lsum[i]=lsum[i-1]+t[i][1]; rsum[i]=rsum[i-1]+t[i][c]; } for (int i=1; i<=r; i++) { hsum[i][1]=t[i][1]; for (int j=2; j<=c; j++) hsum[i][j]=hsum[i][j-1]+t[i][j]; }}void DP(){ for (int i=1; i<=r; i++) dis[i][r+i]=dis[r+i][i]=hsum[i][c]; for (int i=1; i<=r; i++) { for (int j=1; j<i; j++) { int temp=hsum[j][c]+(lsum[i]-lsum[j])+(rsum[i]-rsum[j]); dis[i][r+i]=Min(dis[i][r+i],temp); dis[r+i][i]=Min(dis[r+i][i],temp); } for (int j=i+1; j<=r; j++) { int temp=hsum[j][c]+(lsum[j-1]-lsum[i-1])+(rsum[j-1]-rsum[i-1]); dis[i][r+i]=Min(dis[i][r+i],temp); dis[r+i][i]=Min(dis[r+i][i],temp); } dis[i][i]=t[i][1]; dis[r+i][r+i]=t[i][c]; } for (int i=1; i<=r; i++) { for (int j=i-1; j>=1; j--) { dis[i][j]=Min(dis[i][j+1]+t[j][1],dis[i][r+j+1]+dis[r+j][j]); dis[i][r+j]=Min(dis[i][r+j+1]+t[j][c],dis[i][j+1]+dis[j][r+j]); dis[r+i][j]=Min(dis[r+i][j+1]+t[j][1],dis[r+i][r+j+1]+dis[r+j][j]); dis[r+i][r+j]=Min(dis[r+i][r+j+1]+t[j][c],dis[r+i][j+1]+dis[j][r+j]); } for (int j=i+1; j<=r; j++) { dis[i][j]=Min(dis[i][j-1]+t[j][1],dis[i][r+j-1]+dis[r+j][j]); dis[i][r+j]=Min(dis[i][r+j-1]+t[j][c],dis[i][j-1]+dis[j][r+j]); dis[r+i][j]=Min(dis[r+i][j-1]+t[j][1],dis[r+i][r+j-1]+dis[r+j][j]); dis[r+i][r+j]=Min(dis[r+i][r+j-1]+t[j][c],dis[r+i][j-1]+dis[j][r+j]); } }}int main(){ freopen("1966.in","r",stdin); freopen("1966.out","w",stdout); scanf("%d%d",&r,&c); for (int i=1; i<=r; i++) for (int j=1; j<=c; j++) scanf("%d",&t[i][j]); Preparation(); DP(); scanf("%d",&d); long long ans=t[1][1]; int lx=1,ly=1; for (int i=1; i<=d; i++) { int x,y; scanf("%d%d",&x,&y); ans+=Get(lx,ly,x,y); lx=x; ly=y; } printf("%I64d\n",ans); return 0;}
总结:这次比赛虽然A了前两题,但第三题只有30分,连
- NOIP2017模拟赛(十四)总结
- NOIP2017模拟赛(二)总结
- NOIP2017模拟赛(三)总结
- NOIP2017模拟赛(四)总结
- NOIP2017模拟赛(五)总结
- NOIP2017模拟赛(六)总结
- NOIP2017模拟赛(七)总结
- NOIP2017模拟赛(八)总结
- NOIP2017模拟赛(九)总结
- NOIP2017模拟赛(十一)总结
- NOIP2017模拟赛(十二)总结
- NOIP2017模拟赛(十三)总结
- NOIP2017模拟赛(1) 总结
- NOIP2017模拟赛(2) 总结
- NOIP2017模拟赛(3) 总结
- NOIP2017模拟赛(4) 总结
- NOIP2017模拟赛(5) 总结
- NOIP2017模拟赛(6) 总结
- Hive基础编程入门(一)
- 最大的数
- Linux 下服务自启动的设置
- java单例模式的七种写法
- [HDU]6053 TrickGCD
- NOIP2017模拟赛(十四)总结
- ACM题集以及各种总结大全!
- Til the Cows Come Home
- Password
- 组合数求模
- OPNET LINK : fatal error LNK1181如何解决
- Fox And Two Dots
- hdu 2642 (summerIII J) 二维树状数组
- 【GRE】做题记录和总结