gems gems gems
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 895 Accepted Submission(s): 167
They place the gems in a row and decide to take turns to take gems from left to right.
Alice goes first and takes 1 or 2 gems from the left. After that, on each turn a player can take k or k+1 gems if the other player takes k gems in the previous turn. The game ends when there are no gems left or the current player can't take k or k+1 gems.
Your task is to determine the difference between the total value of gems Alice took and Bob took. Assume both players play optimally. Alice wants to maximize the difference while Bob wants to minimize it.
For each test case:
the first line contains a numbers n (1≤n≤20000);
the second line contains n numbers: V1,V2…Vn. (−100000≤Vi≤100000)
【题意】给一个序列,两个人玩游戏,A先手,第一次取一个或者两个数,然后轮流取,每次取得个数与前一个人相同或多一个,从左到右取,A希望差值越大,B希望差值越小,求最大差值。
【分析】
动规的思路考虑, dp[person][idx][k]
表示 person==1?Bob:Alice
从第 idx 个开始取,能取 k个使得结果最大(最小) 的最优答案。
首先考虑,不考虑取的人,第 k 次最多取 k+1 个宝石。故 (k+1)(k+2)2≤n ,即 k 最大取值在sqrt(n*2)+1 。
故 dp
的最大枚举状态为 2×20000×200 。
此题的最大最小值的上下界在 INT 范围内,使用长整型会 MLE 。由于 dp[person][idx][k]
最大只与 dp[!person][idx+k][k+1]
产生联系,可用滚动数组的方式将第二维缩小。还有一种二维 做法,因为A希望自己的-B的差值大,B希望A-自己的差值小,也就是自己的-A的差值大,也就是说,两个人都希望自己的分数-对方的 结果尽量大,那么第一维就可以删掉。
#include <bits/stdc++.h> #define inf 0x3f3f3f3f #define met(a,b) memset(a,b,sizeof a) #define pb push_back #define mp make_pair #define rep(i,l,r) for(int i=(l);i<=(r);++i) #define inf 0x3f3f3f3f using namespace std; typedef long long ll; const int N = 2e4+50;; const int M = 255; const int mod = 19260817; const int mo=123; const double pi= acos(-1.0); typedef pair<int,int>pii; ll qpow(int x,int qq){ll f=1,p=x;while(qq){if(qq&1)f=f*p%mod;p=1LL*p*p%mod;qq>>=1;}} int n,m,k; int dp[2][M+10][M]; int sum[N]; int getSum(int l,int r){return sum[r]-sum[l-1];} int main(){ int T; scanf("%d",&T); while(T--){ scanf("%d",&n); sum[0]=0; met(dp,0); for(int i=1,x;i<=n;i++){ scanf("%d",&x); sum[i]=sum[i-1]+x; } for(int pos=n;pos;--pos){ int maxk=int(sqrt(2*pos)+1); int remain=n-pos+1; for(int k=1;k<=min(remain,maxk);k++ ){ if(k==remain){ dp[0][pos&M][k]=getSum(pos,n); dp[1][pos&M][k]=-getSum(pos,n); } else{ if(pos+k-1+k<=n){ dp[0][pos&M][k]=dp[1][(pos+k)&M][k]; dp[1][pos&M][k]=dp[0][(pos+k)&M][k]; if(pos+k+k+1-1<=n){ dp[0][pos&M][k]=min(dp[0][pos&M][k],dp[1][(pos+k)&M][k+1]); dp[1][pos&M][k]=max(dp[1][pos&M][k],dp[0][(pos+k)&M][k+1]); } } dp[0][pos&M][k]+=getSum(pos,pos+k-1); dp[1][pos&M][k]-=getSum(pos,pos+k-1); } } } int tmp=0; if(n>=1){ tmp=dp[0][1][1]; if(n>=2) tmp=max(tmp,dp[0][1][2]); } printf("%d\n",tmp); } return 0; }
#include <bits/stdc++.h> #define inf 0x3f3f3f3f #define met(a,b) memset(a,b,sizeof a) #define pb push_back #define mp make_pair #define rep(i,l,r) for(int i=(l);i<=(r);++i) #define inf 0x3f3f3f3f using namespace std; typedef long long ll; const int N = 2e4+50;; const int M = 255; const int mod = 19260817; const int mo=123; const double pi= acos(-1.0); typedef pair<int,int>pii; ll qpow(int x,int qq){ll f=1,p=x;while(qq){if(qq&1)f=f*p%mod;p=1LL*p*p%mod;qq>>=1;}} int n,m,k; int dp[N][M]; int sum[N]; int getSum(int l,int r){return sum[r]-sum[l-1];} int main(){ int T; scanf("%d",&T); while(T--){ scanf("%d",&n); sum[0]=0; met(dp,0); for(int i=1,x;i<=n;i++){ scanf("%d",&x); sum[i]=sum[i-1]+x; } for(int pos=n;pos;--pos){ int maxk=int( sqrt(2*pos)+1 ); int remain=n-pos+1; for(int k=1;k<=min(remain,maxk);k++ ){ if(k==remain){ dp[pos][k]=getSum(pos,n); } else{ if(pos+k-1+k<=n){ dp[pos][k]=dp[pos+k][k]; if(pos+k+k+1-1<=n){ dp[pos][k]=max(dp[pos][k],dp[pos+k][k+1]); } } dp[pos][k]=getSum(pos,pos+k-1)-dp[pos][k]; } } } int tmp=0; if(n>=1){ tmp=dp[1][1]; if(n>=2) tmp=max(tmp,dp[1][2]); } printf("%d\n",tmp); } return 0; }