NOIP2015题解
D1T1模拟
#include<bits/stdc++.h> #define re(i,l,r) for(int i=(l);i<=(r);i++) using namespace std; const int inf=214748364; template<typename Q> void inin(Q &ret) { ret=0;char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); } int n,a[44][44]; int main() { inin(n); int tot=0,x=1,y=n/2+1; while(++tot<=n*n) { a[x][y]=tot; int dx,dy; if(x==1)dx=n;else dx=x-1; if(y==n)dy=1;else dy=y+1; if(a[dx][dy]) if(x==n)dx=1;else dx=x+1,dy=y;else ; x=dx,y=dy; } re(i,1,n)re(j,1,n)printf("%d%c",a[i][j],j==n?'\n':' '); return 0; }
D1T2
由于每个点只有一个出边,所以这张图上每个连通块有且仅有一个环,所以对每个点深搜打标记找最小环即可
#include<bits/stdc++.h> #define re(i,l,r) for(int i=(l);i<=(r);i++) using namespace std; const int inf=214748364; template<typename Q> void inin(Q &ret) { ret=0;char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); } int n; int a[200020],ans=2147483647; int bo[200020],dfn[200020]; void dfs(int x,int sum,int t) { bo[x]=t;dfn[x]=sum; if(bo[a[x]]==t){ans=min(ans,sum-dfn[a[x]]+1);return ;} else if(bo[a[x]])return ; dfs(a[x],sum+1,t); } int main() { inin(n); re(i,1,n)inin(a[i]); re(i,1,n) if(!bo[i])dfs(i,1,i); cout<<ans; return 0; }
D1T3搜搜搜
假设不能出顺子是不是很简单?统计单牌、对子和各种搭配,尽量少出几次。
所以可以单独DFS顺子的情况,对于每种出顺子的方案,再进行上面的方法更新答案
#include<bits/stdc++.h> #define re(i,l,r) for(int i=(l);i<=(r);i++) using namespace std; const int inf=214748364; template<typename Q> void inin(Q &ret) { ret=0;char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); } int a[16],t,n; int ans=2147483647; void dfs(int sum) { if(sum>=ans)return ; int q=0,w=0,e=0; if(a[15]==1)q++; else if(a[15]==2)e++; re(i,2,14)if(a[i]==1)q++;else if(a[i]==2)w++; re(i,2,14)if(a[i]==4) { e++; if(q>1)q-=2;else if(w>1)w-=2;else if(w>0)w--; } re(i,2,14)if(a[i]==3) { e++; if(q>0)q--;else if(w>0)w--; } ans=min(ans,sum+q+w+e); re(i,3,10) { int j=i; for(;j<=14;j++) { a[j]--; if(a[j]<0)break; if(j>=i+4)dfs(sum+1); } if(j==15)j--; while(j>=i)a[j--]++; } re(i,3,12) { int j=i; for(;j<=14;j++) { a[j]-=2; if(a[j]<0)break; if(j>=i+2)dfs(sum+1); } if(j==15)j--; while(j>=i)a[j--]+=2; } re(i,3,13) { int j=i; for(;j<=14;j++) { a[j]-=3; if(a[j]<0)break; if(j>i)dfs(sum+1); } if(j==15)j--; while(j>=i)a[j--]+=3; } } int main() { inin(t),inin(n); while(t--) { memset(a,0,sizeof(a)); ans=2147483647; re(i,1,n) { int aa,b; inin(aa),inin(b); if(aa==0)a[15]++; else if(aa==1)a[14]++; else a[aa]++; } dfs(0); cout<<ans<<"\n"; } return 0; }
D2T1二分答案
二分最小跳跃长度,看能不能在移走不超过m块石头的前提下走到对岸
#include<bits/stdc++.h> #define re(i,l,r) for(int i=(l);i<=(r);i++) using namespace std; const int inf=214748364; template<typename Q> void inin(Q &ret) { ret=0;char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); } int l,n,m; int dis[50050]; bool check(int M) { int now=0,you=m; while(1) { if(now==n)return 1; re(i,now+1,n)if(dis[i]-dis[now]>=M){now=i;break;} else { you--; if(you<0)return 0; } } return 1; } int main() { inin(l),inin(n),inin(m); re(i,1,n)inin(dis[i]);dis[++n]=l; int L=1,R=l,mid,ans=L; while(L<=R) { mid=(L+R)>>1; if(check(mid))L=mid+1,ans=mid; else R=mid-1; } cout<<ans; return 0; }
D2T2 DP
f[k][i][j]表示用了a的前i个字符,分了k段,匹配了b的前j个字符的方案数
#include<bits/stdc++.h> #define re(i,l,r) for(int i=(l);i<=(r);i++) using namespace std; const int inf=214748364; template<typename Q> void inin(Q &ret) { ret=0;char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); } const int mod=1000000007; int n,m,kk; char a[1010],b[220]; int f[2][1010][220]; int main() { inin(n),inin(m),inin(kk); scanf("%s%s",a+1,b+1); re(i,0,n)f[0][i][0]=1; int d=0; re(now,1,kk) { d^=1; re(i,0,n)f[d][i][now-1]=0; re(i,now,m)for(int j=i;j<=n;j++) if(a[j]==b[i]) { f[d][j][i]=((f[d][j-1][i-1]+f[d][j-1][i])%mod+f[d^1][j-1][i-1])%mod; if(j>1)f[d][j][i]=(f[d][j][i]-f[d][j-2][i-1]+mod)%mod; } else f[d][j][i]=f[d][j-1][i]; } cout<<f[d][n][m]; return 0; }
D2T3二分答案+lca
预处理每个运输计划的lca和长度
二分答案mid,要修改的边肯定在所有长度大于mid的运输计划中
所以要求所有长度大于mid的运输计划的边的交集,可以用前缀和解决,最后看交集里有没有删掉它能够使最长的运输计划长度小于mid的边
#include<bits/stdc++.h> #define re(i,l,r) for(int i=(l);i<=(r);i++) using namespace std; const int inf=214748364; template<typename Q> void inin(Q &ret) { ret=0;char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); } int next[600060],head[300030],zhi[600060],ed,t[600060]; int top[300030],fa[300030],son[300030],sz[300030],dis[300030],shen[300030]; int inininin[300030]; void add(int a,int b,int tt) { next[++ed]=head[a],head[a]=ed,zhi[ed]=b,t[ed]=tt; next[++ed]=head[b],head[b]=ed,zhi[ed]=a,t[ed]=tt; } void dfs(int x) { int Max=0;sz[x]=1; for(int i=head[x];i;i=next[i])if(zhi[i]!=fa[x]) { fa[zhi[i]]=x; dis[zhi[i]]=dis[x]+t[i]; shen[zhi[i]]=shen[x]+1; inininin[zhi[i]]=t[i]; dfs(zhi[i]); sz[x]+=sz[zhi[i]]; if(sz[zhi[i]]>Max)Max=sz[zhi[i]],son[x]=zhi[i]; } } void dfs(int x,int t) { if(!x)return ; top[x]=t; dfs(son[x],t); for(int i=head[x];i;i=next[i])if(zhi[i]!=fa[x]&&zhi[i]!=son[x]) dfs(zhi[i],zhi[i]); } int lca(int x,int y) { if(shen[y]>shen[x])swap(x,y); while(top[x]!=top[y]) if(shen[top[x]]<shen[top[y]])y=fa[top[y]]; else x=fa[top[x]]; return shen[x]<shen[y]?x:y; } struct project { int u,v,lca,len; }pp[300030]; int n,m,mmm=2147483647,mmmm,bo[300030]; void ddfs(int x) { for(int i=head[x];i;i=next[i])if(zhi[i]!=fa[x]) { ddfs(zhi[i]); bo[x]+=bo[zhi[i]]; } } bool check(int mid) { memset(bo,0,sizeof(bo)); int cmp=0,sum=0; re(i,1,m)if(pp[i].len>mid) { cmp=max(cmp,pp[i].len-mid); sum++; bo[pp[i].u]++,bo[pp[i].v]++; bo[pp[i].lca]-=2; } ddfs(1); re(i,1,n)if(bo[i]==sum&&inininin[i]>=cmp)return 1; return 0; } int main() { inin(n),inin(m); re(i,2,n) { int q,w,e; inin(q),inin(w),inin(e); add(q,w,e); } re(i,1,m)inin(pp[i].u),inin(pp[i].v); dfs(1); dfs(1,1); re(i,1,m) pp[i].lca=lca(pp[i].u,pp[i].v), pp[i].len=dis[pp[i].u]+dis[pp[i].v]-(dis[pp[i].lca]<<1), mmm=min(mmm,pp[i].len),mmmm=max(mmmm,pp[i].len); int l=0,r=mmmm,mid,ans; while(l<=r) { mid=(l+r)>>1; if(check(mid))r=mid-1,ans=mid; else l=mid+1; } cout<<ans; return 0; }