T1 题意简述:
Description
Input
Output
Data Constraint
解题思路:乍一看这道题是博弈论,然后它就是博弈论。
看到博弈论想什么呢?SG函数...
然而这道题并不是用SG函数...
凉凉。
正解:dp。dp[i][j]表示第i只动物如果报j,有没有必胜策略。
逆推。初始条件即为dp[1~n][m]=0。
考虑a[i]=a[i+1](即:此动物与后一只动物种群相等)
若dp[i+1][j+1~j+k]中有至少一项为真(即:此动物报j可以递推到下一只动物的必胜局面)
那么dp[i][j]=1(即:此动物报j也为必胜局面)
a[i]!=a[i+1]同理。
若dp[i+1][j+1~j+k]中没有一项为真(即:此动物报j可以递推到下一只动物的必败局面)
那么dp[i][j]=1(即:此动物报j为必胜局面)
由于n^3无法在时限内跑过,考虑优化。前缀和优化可省掉一维。
#include#include #include #include #include #include using namespace std;int n,m,k,dp[5010][5010],sum[5010],a[5010];int main(){ freopen("vode.in","r",stdin); freopen("vode.out","w",stdout); scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int j=m-1;j;j--) { for(int i=n;i;i--) { if(a[i]==a[i%n+1]&&sum[i]) dp[i][j]=1; else if(a[i]!=a[i%n+1]&&!sum[i]) dp[i][j]=1; sum[i]+=dp[i%n+1][j]; if(j+k<=m) sum[i]-=dp[i%n+1][j+k]; } sum[n]+=dp[1][j]; }// for(int j=m-1;j;j--)// {// for(int i=n;i;i--)// {// if(a[i]==a[i%n+1])// {// int tmp=0;// for(int l=j+1;l<=min(j+k,m);l++)// tmp+=dp[i%n+1][l];// if(tmp) dp[i][j]=1;// }// else// {// int tmp=0;// for(int l=j+1;l<=min(j+k,m);l++)// tmp+=dp[i%n+1][l];// if(!tmp) dp[i][j]=1;// }// }// } for(int i=1;i<=n;i++) { int flag=0; for(int j=1;j<=k;j++) if(dp[i][j]){printf("%d ",a[i]);flag=1;break;} if(!flag) printf("%d ",a[i]^1); } return 0;}
T2 题意简述:
Description
Input
Output
Data Constraint
解题思路:大水题...
若当前点是路,则向四周连边。
若当前点是路且靠墙,则向不靠墙的一侧最远处连边。
跑一遍SPFA或者dijkstra都可以。
好像没什么不对?70分会告诉你代码错了。
漏了哪里呢?漏掉了不靠墙的路。
注意,走到不靠墙的路时,可以先向四周发射传送门,然后再走到传送门处。
因此,还要加上不靠墙的路向四周最远处连边,边权为离墙最近的道路距离+1。
#include#include #include #include #include #include #include #define INF 0x3f3f3f3fusing namespace std;char s[501];int n,m,a[501][501],head[250001],vis[250001],dis[250001],cnt,S,T;struct uio{ int nxt,to,val;}edge[4000001];void add(int x,int y,int z){ edge[++cnt].nxt=head[x]; edge[cnt].to=y; edge[cnt].val=z; head[x]=cnt;}void spfa(){ memset(dis,0x3f,sizeof(dis)); queue que; while(!que.empty()) que.pop(); vis[S]=1; dis[S]=0; que.push(S); while(!que.empty()) { int x=que.front(); vis[x]=0; que.pop(); for(int i=head[x];i;i=edge[i].nxt) { int y=edge[i].to; if(dis[y]>dis[x]+edge[i].val) { dis[y]=dis[x]+edge[i].val; if(!vis[y]) que.push(y),vis[y]=1; } } }}int main(){ freopen("portal.in","r",stdin); freopen("portal.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%s",s+1); for(int j=1;j<=m;j++) { if(s[j]!='#') a[i][j]=1; if(s[j]=='C') S=(i-1)*m+j; if(s[j]=='F') T=(i-1)*m+j; } } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { if(!a[i][j]) continue; int x=(i-1)*m+j; if(a[i+1][j]) add(x,x+m,1); if(a[i-1][j]) add(x,x-m,1); if(a[i][j+1]) add(x,x+1,1); if(a[i][j-1]) add(x,x-1,1); int k1=0; while(a[i+k1+1][j]) k1++; int k2=0; while(a[i-k2-1][j]) k2++; int k3=0; while(a[i][j+k3+1]) k3++; int k4=0; while(a[i][j-k4-1]) k4++; int k=min(k1,min(k2,min(k3,k4))); if(k1!=0) add(x,x+k1*m,k+1); if(k2!=0) add(x,x-k2*m,k+1); if(k3!=0) add(x,x+k3,k+1); if(k4!=0) add(x,x-k4,k+1); } spfa(); if(dis[T]==INF) printf("nemoguce\n"); else printf("%d\n",dis[T]); return 0;}
T3 题意简述:
Description
Input
Output
Data Constraint
解题思路:并查集/CDQ分治。
这里给出并查集做法。
考虑对每一组加边进行一组并查集操作。
每次操作对儿子赋予一个权值,m-i+1。
答案即为x到y的最短路径上的最大值。
由于要求最大值,故不能进行路径压缩,只能按秩合并。
感谢ErkkiErkko大佬及Menteur_Hxy大佬的帮助。
#include#include #include #include #include #include #define INF 0x3f3f3f3fusing namespace std;int n,m,ask,fa[100001],siz[100001],val[100001],dep[100001];int find(int x){ if(x==fa[x]) return x; dep[x]=dep[fa[x]]+1; return find(fa[x]);}void add(int x,int y,int z){ int xx=find(x); int yy=find(y); if(xx!=yy) { if(siz[xx]>siz[yy]) fa[yy]=xx,siz[xx]=max(siz[xx],siz[yy]+1),val[yy]=z; else fa[xx]=yy,siz[yy]=max(siz[yy],siz[xx]+1),val[xx]=z; }}int query(int x,int y){ int ansx=0,ansy=0; if(dep[x] dep[y]) ansx=max(ansx,val[x]),x=fa[x]; while(x!=y) { ansx=max(ansx,val[x]),x=fa[x]; ansy=max(ansy,val[y]),y=fa[y]; } return max(ansx,ansy);}int main(){ freopen("pictionary.in","r",stdin); freopen("pictionary.out","w",stdout); scanf("%d%d%d",&n,&m,&ask); for(int i=1;i<=n;i++) fa[i]=i,siz[i]=1; for(int i=m;i;i--) for(int j=2*i;j<=n;j+=i) add(j-i,j,m-i+1); for(int i=1;i<=ask;i++) { int u,v; scanf("%d%d",&u,&v); printf("%d\n",query(u,v)); } return 0;}