noip2014 提高组
Posted 友人A
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了noip2014 提高组相关的知识,希望对你有一定的参考价值。
T1 生活大爆炸版 石头剪刀布 题目传送门
就是道模拟题咯
#include<algorithm> #include<cstdio> #include<cstring> using namespace std; int read(){ int ans=0,f=1,c=getchar(); while(c<‘0‘||c>‘9‘){if(c==‘-‘) f=-1; c=getchar();} while(c>=‘0‘&&c<=‘9‘){ans=ans*10+(c-‘0‘); c=getchar();} return ans*f; } int a,b,n; int x[251],y[251],g[251],f[251]; int w[6][6]={{2,0,1,1,0},{1,2,0,1,0},{0,1,2,0,1},{0,0,1,2,1},{1,1,0,0,2}}; int main() { n=read(); int la=read(),lb=read(); for(int i=0;i<la;i++) x[i]=read(); for(int i=0;i<lb;i++) y[i]=read(); for(int i=0;i<n;i++) g[i]=x[i%la],f[i]=y[i%lb]; for(int i=0;i<n;i++){ if(w[g[i]][f[i]]==0) b++; if(w[g[i]][f[i]]==1) a++; } printf("%d %d\n",a,b); return 0; }
T2 联合权值 题目传送门
易证明和某一个点相连接的点 他们之间的距离就是2 所以我们可以枚举每一个点求值 当然一个一个点去求值太慢
这个时候我们发现了一个神奇的东西 他叫做——加法结合律! 问题就完美解决了.
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int M=450007,mod=10007; int read(){ int ans=0,f=1,c=getchar(); while(c<‘0‘||c>‘9‘){if(c==‘-‘) f=-1; c=getchar();} while(c>=‘0‘&&c<=‘9‘){ans=ans*10+(c-‘0‘); c=getchar();} return ans*f; } int n,first[M],cnt,ans,mx,w[M]; struct node{int to,next;}e[M]; void ins(int a,int b){cnt++; e[cnt].to=b; e[cnt].next=first[a]; first[a]=cnt;} void insert(int a,int b){ins(a,b); ins(b,a);} void dfs(int x){ int mx1=0,mx2=0,sum=0; for(int i=first[x];i;i=e[i].next){ int now=e[i].to; sum=(sum+w[now])%mod; if(w[now]>mx1) mx2=mx1,mx1=w[now]; else if(w[now]>mx2) mx2=w[now]; } mx=max(mx,mx1*mx2); for(int i=first[x];i;i=e[i].next){ int now=e[i].to; ans=(ans+w[now]*((sum-w[now])%mod+mod)%mod)%mod; } } int main() { int x,y; n=read(); for(int i=1;i<n;i++) x=read(),y=read(),insert(x,y); for(int i=1;i<=n;i++) w[i]=read(); for(int i=1;i<=n;i++) dfs(i); printf("%d %d\n",mx,ans); return 0; }
T3 飞扬的小鸟 题目传送门
这就是道dp然而看了眼题解自己YY了半天才Ac......主要还是细节处理的问题吧?码力太差
首先很容易想到o(nm*m)的算法 直接推出答案 但是明显会超时 很容易得到f[i][j]=min{f[i-1][j-k*x]+k}
那较小的点会被计算很多次 我们可以由每个点的下面f【i】【j-x】的点推出答案 仍为最优解 这样就可以得出新的方程f[i][j]=min{f[i-1][j-x],f[i][j-x]}
复杂度降下来了就可以写了 当然还可以由上方下降得到 所以我们可以分两次递推得出答案 还有游戏到高度为M的时候不会结束 所以还得特殊考虑
最后 这个游戏不是codevs那里的东东嘛?
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxN=15007,maxM=1507,inf=1000000000; int read(){ int ans=0,f=1,c=getchar(); while(c<‘0‘||c>‘9‘){if(c==‘-‘) f=-1; c=getchar();} while(c>=‘0‘&&c<=‘9‘){ans=ans*10+(c-‘0‘); c=getchar();} return ans*f; } int f[maxN][maxM]; int n,m,k,x[maxN],y[maxN]; int down[maxN],up[maxN]; int main() { n=read(); m=read(); k=read(); for(int i=0;i<=n;i++) down[i]=0,up[i]=m+1; for(int i=0;i<n;i++) x[i]=read(),y[i]=read(); for(int i=1;i<=k;i++){ int p=read(); down[p]=read(); up[p]=read(); } for(int i=1;i<=n;i++) for(int j=0;j<=m;j++) f[i][j]=inf; f[0][0]=inf;//for(int i=1;i<=n;i++,printf("\n")) for(int j=1;j<=m;j++) printf("[%d] ",f[i][j]); //for(int i=1;i<=n;i++) printf("[%d %d]\n",down[i],up[i]); //for(int i=0;i<n;i++) printf("[%d %d]\n",x[i],y[i]); for(int i=1;i<=n;i++){ for(int j=x[i-1];j<=m;j++) f[i][j]=min(f[i-1][j-x[i-1]]+1,f[i][j-x[i-1]]+1); for(int j=m-x[i-1];j<=m;j++) f[i][m]=min(f[i][m],f[i][j]+1),f[i][m]=min(f[i][m],f[i-1][j]+1); for(int j=down[i]+1;j<=up[i]-1;j++) if(j+y[i-1]<=m) f[i][j]=min(f[i][j],f[i-1][j+y[i-1]]); for(int j=1;j<=down[i];j++) f[i][j]=inf;; for(int j=up[i];j<=m;j++) f[i][j]=inf; } int ans=inf,cnt=k; for(int i=n;i;i--){ for(int j=down[i]+1;j<=up[i]-1;j++) ans=min(ans,f[i][j]); if(ans<inf) break; if(up[i]!=m+1) cnt--; } if(cnt==k) printf("1\n%d",ans); else printf("0\n%d",cnt); return 0; }
T4 无线网络发射器选址 题目传送门
枚举 计算 比较大小 没什么好说的吧
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int read(){ int ans=0,f=1,c=getchar(); while(c<‘0‘||c>‘9‘){if(c==‘-‘) f=-1; c=getchar();} while(c>=‘0‘&&c<=‘9‘){ans=ans*10+(c-‘0‘); c=getchar();} return ans*f; } int d,n,ans,sum; int map[155][155]; int main() { int x,y,k; d=read(); n=read(); for(int i=1;i<=n;i++) x=read(),y=read(),k=read(),map[x][y]=k; for(int i=0;i<=128;i++) for(int j=0;j<=128;j++){ int now=0; for(int x=max(0,i-d);x<=min(i+d,128);x++) for(int y=max(0,j-d);y<=min(j+d,128);y++) now+=map[x][y]; if(ans<now) ans=now,sum=0; if(ans==now) sum++; } printf("%d %d\n",sum,ans); return 0; }
T5 寻找道路 题目传送门
首先可以顺着终点反向bfs一波 记录那些点是可以到达终点的
然后枚举每一个点看他的出边所指向的点是否能到达终点就好了
然后顺着可以走的点走一波spfa就解决问题了
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int M=20007,maxN=400007,inf=0x3f3f3f3f; int read(){ int ans=0,f=1,c=getchar(); while(c<‘0‘||c>‘9‘){if(c==‘-‘) f=-1; c=getchar();} while(c>=‘0‘&&c<=‘9‘){ans=ans*10+(c-‘0‘); c=getchar();} return ans*f; } int first[M],book[M]; int d[M],h[M],cnt,S,T; int n,m,q[M],use[M]; struct node{int to,next;}e[maxN]; void insert(int a,int b){cnt++; e[cnt].to=b; e[cnt].next=first[a]; first[a]=cnt;} int sum,last[M]; struct note{int to,next;}e1[maxN]; void ins(int a,int b){sum++; e1[sum].to=b; e1[sum].next=last[a]; last[a]=sum;} void bfs(){ int head=0,tail=1; h[T]=1; while(head!=tail){ int x=q[head++]; for(int i=last[x];i;i=e1[i].next){ int now=e1[i].to; if(!h[now]){h[now]=1; q[tail++]=now;} } } //for(int i=1;i<=n;i++) printf("[%d] ",h[i]); printf("\n"); use[T]=use[S]=1; // for(int x=1;x<=n;x++,printf("\n")) // for(int i=first[x];i;i=e[i].next) printf("[%d] ",e[i].to); for(int x=1;x<=n;x++){ int now=0; for(int i=first[x];i;i=e[i].next){ now=e[i].to; if(!h[now]) break; } if(!h[now]) continue; use[x]=1; } //for(int i=1;i<=n;i++) printf("[%d] ",use[i]); printf("\n"); } void spfa(){ memset(d,0x3f,sizeof(d)); int head=0,tail=1; d[S]=0; q[head]=S; book[S]=1; while(head!=tail){ int x=q[head++]; book[x]=0; if(head>M) head=0; for(int i=first[x];i;i=e[i].next){ int now=e[i].to; if(!use[now]) continue; //printf("[%d]\n",now); if(d[now]>d[x]+1){ d[now]=d[x]+1; if(!book[now]){q[tail++]=now; book[now]=1; if(tail>M) tail=0;} } } } } int main() { int x,y; n=read(); m=read(); for(int i=1;i<=m;i++){ x=read(); y=read(); if(x!=y) insert(x,y),ins(y,x); } S=read(); T=read(); q[0]=T; bfs(); spfa(); if(d[T]<inf) printf("%d\n",d[T]); else printf("-1\n"); return 0; }
T6 解方程 题目传送门
这道题确实难 我是照着黄学长的思路来的 神犇传送门
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int read(){ int ans=0,f=1,c=getchar(); while(c<‘0‘||c>‘9‘){if(c==‘-‘) f=-1; c=getchar();} while(c>=‘0‘&&c<=‘9‘){ans=ans*10+(c-‘0‘); c=getchar();} return ans*f; } int mod[5]={11261,19997,22877,21893,14843}; int n,m,len,sum; int ans[1000005]; int a[5][105],pre[5][105],res[5][30005]; char s[10005]; int calc(int k){ int sum=0; for(int i=0;i<=n;i++) sum=(sum+a[k][i]*pre[k][i])%mod[k]; if(sum<0) sum+=mod[k]; return sum; } int pd(int x){ for(int k=0;k<5;k++) if(res[k][x%mod[k]]) return 0; return 1; } int main() { n=read(); m=read(); for(int i=0;i<=n;i++){ scanf("%s",s+1); len=strlen(s+1); bool f=0; for(int k=0;k<5;k++){ if(s[1]==‘-‘) f=1,a[k][i]=0; else a[k][i]=s[1]-‘0‘; } for(int k=0;k<5;k++){ for(int j=2;j<=len;j++) a[k][i]=(a[k][i]*10+s[j]-‘0‘)%mod[k]; if(f) a[k][i]=-a[k][i]; } } for(int k=0;k<5;k++){ for(int x=1;x<mod[k];x++){ pre[k][0]=1; for(int i=1;i<=n;i++) pre[k][i]=(pre[k][i-1]*x)%mod[k]; res[k][x]=calc(k); } } for(int i=1;i<=m;i++) if(pd(i)) ans[++sum]=i; printf("%d\n",sum); for(int i=1;i<=sum;i++) printf("%d\n",ans[i]); return 0; }
以上是关于noip2014 提高组的主要内容,如果未能解决你的问题,请参考以下文章