CF1728D
Posted Willette
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1728D相关的知识,希望对你有一定的参考价值。
博弈论dp模板题
首先我们可以先确定dp状态 dp[round][L][R][0/1]表示第round轮,现在字符串为[L~R],上一轮的人取了左边还是右边
然后发现round是可以由字符串L~R确定而来的,因为每一轮只删除一个数,因此可以优化round这维
我们令dp[L][R][0/1]=1为 Alice 赢,dp[L][R][0/1]=0为平局,dp[L][R][0/1]=-1为Bob胜利
对于Alice是先手,所以我们只需要ans尽量大即可:
if(round&1) //A的轮次 ans=max(dfs(L+1,R,0),dfs(L,R-1,1));
对于Bob是后手,所以每次都要都还要考虑 Alice 选了啥:
其实也就四种情况:
1.Alice选了L-1,Bob选了L
2.Alice选了L-1,Bob选了R
3.Alice选了R+1,Bob选了L
4.Alice选了R+1,Bob选了R
然后让ans尽可能小就行了
#include<bits/stdc++.h> using namespace std; #define ll long long #define mp make_pair #define pb push_back #define popb pop_back #define fi first #define se second #define popcount __builtin_popcount const int N=2010; //const int M=; const int inf=1e9; //const ll INF=1e18; int T,n,dp[N][N][2]; char s[N]; inline int read() int x=0,f=1;char ch=getchar(); while(ch<\'0\'||ch>\'9\')if(ch==\'-\')f=-1;ch=getchar(); while(ch>=\'0\'&&ch<=\'9\')x=(x<<1)+(x<<3)+(ch^48);ch=getchar(); return x*f; int dfs(int L,int R,int op) int round=n-(R-L+1)+1; if(dp[L][R][op]!=inf) return dp[L][R][op]; int ans; if(round&1) //A的轮次 ans=max(dfs(L+1,R,0),dfs(L,R-1,1)); else //B的轮次 ans=inf; if(op==0) // A选了L-1的位置 // B选了L的位置 if(dfs(L+1,R,0)==1) ans=min(ans,1); else if(dfs(L+1,R,0)==-1) ans=min(ans,-1); else if(s[L-1]==s[L]) ans=min(ans,0); if(s[L-1]>s[L]) ans=min(ans,1); if(s[L-1]<s[L]) ans=min(ans,-1); // B选了R的位置 if(dfs(L,R-1,1)==1) ans=min(ans,1); else if(dfs(L,R-1,1)==-1) ans=min(ans,-1); else if(s[L-1]==s[R]) ans=min(ans,0); if(s[L-1]>s[R]) ans=min(ans,1); if(s[L-1]<s[R]) ans=min(ans,-1); else // A选了 R+1 的位置 // B选了L的位置 if(dfs(L+1,R,0)==1) ans=min(ans,1); else if(dfs(L+1,R,0)==-1) ans=min(ans,-1); else if(s[R+1]==s[L]) ans=min(ans,0); if(s[R+1]>s[L]) ans=min(ans,1); if(s[R+1]<s[L]) ans=min(ans,-1); // B选了R的位置 if(dfs(L,R-1,1)==1) ans=min(ans,1); else if(dfs(L,R-1,1)==-1) ans=min(ans,-1); else if(s[R+1]==s[R]) ans=min(ans,0); if(s[R+1]>s[R]) ans=min(ans,1); if(s[R+1]<s[R]) ans=min(ans,-1); return dp[L][R][op]=ans; int main() // freopen("","r",stdin); // freopen("","w",stdout); // ios::sync_with_stdio(0); // cin.tie(0); T=read(); while(T--) scanf("%s",s+1); n=strlen(s+1); for(int i=1;i<=n;i++) for(int j=i;j<=n;j++) dp[i][j][0]=dp[i][j][1]=inf; int op=dfs(1,n,0); if(op==1) puts("Alice"); else if(op==0) puts("Draw"); else if(op==-1) puts("Bob"); return 0;
IndiaHacks 2016 - Online Edition (CF) . D
这题思路很简单,二分m,求最大流是否大于等于x。
但是比赛过程中大部分的代码都被hack了。。。
精度问题,和流量可能超int
关于精度问题,这题真是提醒的到位,如果是先用二分将精度控制在10^-8左右,最后乘一个10^4,精度只能在10-4,而二分控制精度在10^-11很容易死循环(因为double 保存15-16位有效数字,结果可能为10^6级,精确到10-11,double做不到)
所以这题二分可以不写成while(d-b>eps),而直接规定二分的次数,设置成100次,基本可以保证14-15位有效数字都正确了,这时再乘10^4还是能够达到题目中要求的10^-6的精度。
还有一种处理精度的方法:
直接定义上下界就为输出的最后结果,在判断的过程中除以x,最后输出也能满足要求。
第一种精度处理方式:
#include <stdio.h> #include <string.h> #include <algorithm> #include <vector> #include <math.h> #include <iostream> using namespace std; #define eps 1e-11 #define N 55 #define M 500500 #define INF 0x3fffff struct node1 { long long to,w,next; }edge[M]; long long sn,sm,sx; long long pre[10*N]; long long g[N][N]; long long gap[10*N],lv[10*N]; long long k,c,m; long long cnt; long long n,nn; long long s,t; long long ans; long long sum; void add_edge(long long u,long long v,long long w) { edge[cnt].to=v; edge[cnt].w=w; edge[cnt].next=pre[u]; pre[u]=cnt++; } long long gdfs(long long k,long long w) { if(k==t) return w; long long f=0; long long mi=nn-1; for(long long p=pre[k];p!=-1;p=edge[p].next) { long long v=edge[p].to,tw=edge[p].w; if(tw!=0) { if(lv[k]==lv[v]+1) { long long tmp=gdfs(v,min(tw,w-f)); f+=tmp; edge[p].w-=tmp; edge[p^1].w+=tmp; if(f==w||lv[s]==nn) break; } if(lv[v]<mi) mi=lv[v]; } } if(f==0) { gap[lv[k]]--; if( gap[ lv[k] ]==0 ) { lv[s]=nn; } lv[k]=mi+1; gap[lv[k]]++; } return f; } long long sap() { memset(lv,0,sizeof(lv)); memset(gap,0,sizeof(gap)); gap[0]=nn; while(lv[s]<nn) { sum+=gdfs(s,INF); } return sum; } long long a[505],b[505],kk[505]; long long check(double mid) { sum=0; //mid/=sx; memset(pre,-1,sizeof(pre)); cnt=0; for(long long i=0;i<sm;i++) { add_edge(a[i],b[i],(long long)(kk[i]/mid+eps)); add_edge(b[i],a[i],0); } if(sap()>=sx) { return 1; } else return 0; } int main() { cin>>sn>>sm>>sx; for(long long i=0;i<sm;i++) { cin>>a[i]>>b[i]>>kk[i]; } s=1; t=sn; nn=t+1; //这个精度问题还是很坑。。。 double b=0,d=10000000.0; //好坑的东西! 我就操! int time=160; while(time--)//这里精度太小,竟然会死循环。。。 { double mid=(b+d)/2; if( check(mid)==1 ) { b = mid; } else { d = mid; } } printf("%.10lf",b*sx); return 0; }
第二种精度处理方式:
#include <stdio.h> #include <string.h> #include <algorithm> #include <vector> #include <math.h> #include <iostream> using namespace std; #define eps 1e-11 #define N 55 #define M 500500 #define INF 0x3fffff struct node1 { long long to,w,next; }edge[M]; long long sn,sm,sx; long long pre[10*N]; long long g[N][N]; long long gap[10*N],lv[10*N]; long long k,c,m; long long cnt; long long n,nn; long long s,t; long long ans; long long sum; void add_edge(long long u,long long v,long long w) { edge[cnt].to=v; edge[cnt].w=w; edge[cnt].next=pre[u]; pre[u]=cnt++; } long long gdfs(long long k,long long w) { if(k==t) return w; long long f=0; long long mi=nn-1; for(long long p=pre[k];p!=-1;p=edge[p].next) { long long v=edge[p].to,tw=edge[p].w; if(tw!=0) { if(lv[k]==lv[v]+1) { long long tmp=gdfs(v,min(tw,w-f)); f+=tmp; edge[p].w-=tmp; edge[p^1].w+=tmp; if(f==w||lv[s]==nn) break; } if(lv[v]<mi) mi=lv[v]; } } if(f==0) { gap[lv[k]]--; if( gap[ lv[k] ]==0 ) { lv[s]=nn; } lv[k]=mi+1; gap[lv[k]]++; } return f; } long long sap() { memset(lv,0,sizeof(lv)); memset(gap,0,sizeof(gap)); gap[0]=nn; while(lv[s]<nn) { sum+=gdfs(s,INF); } return sum; } long long a[505],b[505],kk[505]; long long check(long double mid) { sum=0; mid/=sx; memset(pre,-1,sizeof(pre)); cnt=0; for(long long i=0;i<sm;i++) { add_edge(a[i],b[i],(long long)(kk[i]/mid+eps)); add_edge(b[i],a[i],0); } if(sap()>=sx) { return 1; } else return 0; } int main() { cin>>sn>>sm>>sx; for(long long i=0;i<sm;i++) { cin>>a[i]>>b[i]>>kk[i]; } s=1; t=sn; nn=t+1; //这个精度问题还是很坑。。。 long double b=0,d=1000000000.0; //好坑的东西! 我就操! while(d-b > 1e-13)//这里精度太小,竟然会死循环。。。 { long double mid=(b+d)/2; if( check(mid)==1 ) { b = mid; } else { d = mid; } } printf("%.20Lf",b); return 0; }
以上是关于CF1728D的主要内容,如果未能解决你的问题,请参考以下文章
[CF930E]/[CF944G]Coins Exhibition