noip 2017 提高组
Posted 友人A
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了noip 2017 提高组相关的知识,希望对你有一定的参考价值。
T1 神奇的幻方 题目传送门 就只是一道模拟题 水水水
#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 map[55][55],x[2507],y[2507],n; int main() { n=read(); map[1][(n+1)/2]=1; x[1]=1; y[1]=(n+1)/2; for(int i=2;i<=n*n;i++){ int nx=x[i-1],ny=y[i-1]; if(nx==1&&ny<n) map[n][ny+1]=i,x[i]=n,y[i]=ny+1; else if(nx!=1&&ny==n) map[nx-1][1]=i,x[i]=nx-1,y[i]=1; else if(nx==1&&ny==n) map[nx+1][ny]=i,x[i]=nx+1,y[i]=ny; else if(nx!=1&&ny!=n){ if(!map[nx-1][ny+1]) map[nx-1][ny+1]=i,x[i]=nx-1,y[i]=ny+1; else map[nx+1][ny]=i,x[i]=nx+1,y[i]=ny; } } for(int i=1;i<=n;i++,printf("\\n")) for(int j=1;j<=n;j++) printf("%d ",map[i][j]); return 0; }
T2 信息传递 题目传送门
这道题呢 搞一波tarjan缩点 最小的环就是答案了哇 不过一个点自成一环的不能算
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int M=250007; 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,ans=M; int top,st[M],book[M]; int low[M],dfn[M],sum; int first[M],cnt; struct node{int to,next;}e[2*M]; void ins(int a,int b){sum++; e[sum].to=b; e[sum].next=first[a]; first[a]=sum;} void dfs(int x){ dfn[x]=low[x]=++sum; st[++top]=x; book[x]=1; for(int i=first[x];i;i=e[i].next){ int now=e[i].to; if(!dfn[now]){ dfs(now); low[x]=min(low[x],low[now]); } if(book[now]) low[x]=min(low[x],dfn[now]); } if(low[x]==dfn[x]){ int sum=1; book[x]=0; while(st[top]!=x){ int now=st[top--]; book[now]=0; sum++; } top--; if(sum>1) ans=min(ans,sum); } } int main() { int x; n=read(); for(int i=1;i<=n;i++) x=read(),ins(i,x); for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i); printf("%d\\n",ans); return 0; }
T3 斗地主 题目传送门
很佩服写这道题的人 我比较懒所以就跳了...23333
好的跑回来补题了 其实这道题没有想象中那么恶心
考虑到如果没有顺子出牌次数应该是一定的
所以dfs枚举顺子的怎么打 然后就算一波答案就好啦
orz vijos的一百个测试数据
#include<cstdio> #include<cstring> #include<algorithm> #define LL long long using namespace std; const int 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 T,n,x,ans; int num[15],sum[15]; int calc(){ int cnt=0,f=0; memset(sum,0,sizeof(sum)); for(int i=0;i<=13;i++) sum[num[i]]++; if(num[0]==2) f=1; while(sum[4]&&sum[2]>=2) cnt++,f=0,sum[4]--,sum[2]-=2; while(sum[4]&&sum[1]>=2) cnt++,sum[4]--,sum[1]-=2; while(sum[4]&&sum[2]) cnt++,f=0,sum[4]--,sum[2]--; if(f) cnt++,sum[2]--; while(sum[3]&&sum[2]) cnt++,sum[3]--,sum[2]--; while(sum[3]&&sum[1]) cnt++,sum[3]--,sum[1]--; return cnt+sum[1]+sum[2]+sum[3]+sum[4]; } void dfs(int step){ if(step>=ans) return ; ans=min(ans,step+calc()); for(int i=2;i<=13;i++){ int now=i; while(num[now]>=3) now++; if(now-i>=2){ for(int j=i+1;j<now;j++){ for(int k=i;k<=j;k++) num[k]-=3; dfs(step+1); for(int k=i;k<=j;k++) num[k]+=3; } } } for(int i=2;i<=13;i++){ int now=i; while(num[now]>=2) now++; if(now-i>=3){ for(int j=i+2;j<now;j++){ for(int k=i;k<=j;k++) num[k]-=2; dfs(step+1); for(int k=i;k<=j;k++) num[k]+=2; } } } for(int i=2;i<=13;i++){ int now=i; while(num[now]) now++; if(now-i>=5){ for(int j=i+4;j<now;j++){ for(int k=i;k<=j;k++) num[k]--; dfs(step+1); for(int k=i;k<=j;k++) num[k]++; } } } } int pd(int x){ if(!x) return x; return x==1?13:x-1; } int main() { T=read(); n=read(); while(T--){ memset(num,0,sizeof(num)); for(int i=1;i<=n;i++) x=pd(read()),read(),num[x]++; ans=inf; dfs(0); printf("%d\\n",ans); } 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 s[50007],n,m,v; int l,r,k,old; int pd(int w){ int ans=0,sum=0; for(int i=1;i<=n;i++) { if(s[i]-sum<=w) ans++; else sum=s[i]; } return ans<=m; } int main() { v=read(); n=read(); m=read(); l=0; r=v+1; for(int i=1;i<=n;i++) s[i]=read(); n++; s[n]=v; while(l<=r){ int mid=(l+r)>>1; if(pd(mid)) l=mid+1; else r=mid-1; } printf("%d\\n",l); return 0; }
T5 子串 题目传送门 这道题就是个DP 自己讲得不好 推荐个博客吧 orz
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int M=1507,mod=1000000007; 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,m,cnt,now,last=1; char a[M],b[M]; int f[2][M][M],s[2][M][M]; int main() { n=read(); m=read(); cnt=read(); //printf("[%d %d %d]\\n",n,m,cnt); scanf("%s %s",a+1,b+1); //printf("%s %s",a+1,b+1); s[0][0][0]=s[1][0][0]=1; for(int i=1;i<=n;i++){ now^=1; last^=1; for(int j=1;j<=m;j++){ if(a[i]==b[j]) for(int k=1;k<=cnt;k++) f[now][j][k]=(f[last][j-1][k]+s[last][j-1][k-1])%mod,s[now][j][k]=(s[last][j][k]+f[now][j][k])%mod; else for(int k=1;k<=cnt;k++) f[now][j][k]=0,s[now][j][k]=s[last][j][k]; } } printf("%d\\n",s[n%2][m][cnt]); return 0; }
T6 运输计划 题目传送门
这是道lca加二分 果然自己还是太弱了没写出来 看了波题解才懂的 orzzsn 推荐个博客吧
我感觉吧 sum处理的时候就像是打标记一样所以sum【l【i】】++,sum【r【i】】++,sum【lca【i】-=2; 就是把l【i】到r【i】的路径打一波标记好处理 2333
具体看思诺大爷的题解吧 orz
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int M=350007; 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 l[M],r[M],lca[M],dis[M],deep[M],f[M][25],sum[M],v[M],T[M],vis[M]; int n,m,x,y,w; int cnt,first[M]; struct node{int to,next,w;}e[2*M]; void ins(int a,int b,int w){cnt++; e[cnt].to=b; e[cnt].w=w; e[cnt].next=first[a]; first[a]=cnt;} void insert(int a,int b,int w){ins(a,b,w); ins(b,a,w);} void dfs(int x){ vis[x]=1; for(int i=1;(1<<i)<=deep[x];i++) f[x][i]=f[f[x][i-1]][i-1]; for(int i=first[x];i;i=e[i].next){ int now=e[i].to; if(!vis[now]){ deep[now]=deep[x]+1; v[now]=e[i].w; dis[now]=dis[x]+v[now]; f[now][0]=x; dfs(now); } } } int find(int x,int y){ if(deep[x]<deep[y]) swap(x,y); int d=deep[x]-deep[y]; for(int i=0;(1<<i)<=d;i++) if((1<<i)&d) x=f[x][i]; if(x==y) return x; for(int i=25;i>=0;i--) if((1<<i)<=deep[x]&&f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } void push_sum(int x){ for(int i=first[x];i;i=e[i].next){ int now=e[i].to; if(now!=f[x][0]) push_sum(now),sum[x]+=sum[now]; } } int check(int mid){ int cnt=0,cmax=0; for(int i=1;i<=n;i++) sum[i]=0; for(int i=1;i<=m;i++) if(T[i]>mid){ cnt++; cmax=max(cmax,T[i]-mid); sum[l[i]]++; sum[r[i]]++; sum[lca[i]]-=2; } push_sum(1); for(int i=1;i<=n;i++) if(sum[i]==cnt&&v[i]>=cmax) return 1; return 0; } int main() { n=read(); m=read(); for(int i=1;i<n;i++) x=read(),y=read(),w=read(),insert(x,y,w); dfs(1); for(int i=1;i<=m;i++){ l[i]=read(); r[i]=read(); lca[i]=find(l[i],r[i]); T[i]=dis[l[i]]+dis[r[i]]-2*dis[lca[i]]; } //for(int i=1;i<=m;i++) printf("[%d %d %d %d]\\n",l[i],r[i],lca[i],T[i]); int L=0,R=0; for(int i=1;i<=m;i++) R=max(R,T[i]); while(L<=R){ int mid=(L+R)>>1; if(check(mid)) R=mid-1; else L=mid+1; } printf("%d\\n",L); return 0; }
以上是关于noip 2017 提高组的主要内容,如果未能解决你的问题,请参考以下文章
noip2012提高组复赛的所有知识点,要详细精确到每种算法。