【Codeforces 738F】 Financiers Game【記憶化DP】
阿新 • • 發佈:2018-11-15
題意:
有一個數列,兩個人分別從兩端開始取數字,左邊的先取,第一次能取1個或2個,然後輪流取得時候,如果第一個取了k個,後一個人只能取k或k+1個,如果剩下的不夠了則遊戲終止,I想要最大化兩個人取得數字之和的差距,Z想要最小化,兩個人都選擇最優操作
題解:
重點是空間時間複雜度
上述演算法看起來是n3次的dp[L][R][K]
但實際上L最多隻能達到2000多一點的樣子(I多拿一次數字的情況下
K需要從一開始增加,從1開始增加到最大1,2,……,k sum=k*(k+1)/2 k<=sqrt(2*n)也就是90左右
在來看R,R代表的是Z先生拿到的位置,設d為I與Z取走數字數量之差,d=(n - r) - (l - 1) 取左右100就200吧
所以最終我們只需要dp[2100][200][100][2];
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> using namespace std; int n; int a[4005]; int dp[2100][200][100][2]; bool used[2100][200][100][2]; int sum[4005]; int dfs(int l,int d,int k,int t) { if(used[l][d][k][t]!=0) return dp[l][d][k][t]; used[l][d][k][t]=1; int dis=d-100; int cntr=l+dis; int r=n+1-cntr; int tans; if(t==0) { if(l+k<r) { tans=dfs(l+k,d-k,k,1); if(l+k+1<r) { tans=max(tans,dfs(l+k+1,d-k-1,k+1,1)); } } else { tans=(sum[l]-sum[0])-(sum[n]-sum[r-1]); } } else { if(r-k>l) { tans=dfs(l,d+k,k,0); if(r-k-1>l) { tans=min(tans,dfs(l,d+k+1,k+1,0)); } } else { tans=(sum[l]-sum[0])-(sum[n]-sum[r-1]); } } return (dp[l][d][k][t]=tans); } int main() { while(~scanf("%d",&n)) { memset(used,0,sizeof(used)); //cout<<dp[123][32][34][1]<<endl; sum[0]=0; for(int i=1;i<=n;i++) { scanf("%d",&a[i]); sum[i]=sum[i-1]+a[i]; } int ans=dfs(0,100,1,0); printf("%d\n",ans); } }