gems gems gems
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 476 Accepted Submission(s): 53
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)
dp[i][j]表示以第i个数开始,当前先手选择连续j个的最大差值。无需考虑具体是哪个人操作,每个人都希望到自己时自己的值与对方的值差尽可能的大,故只需开二维即可。
转移方程为 dp[i][j]=min(-dp[i+j][j]+sum[i+j-1]-sum[i-1],-dp[i+j][j+1]+sum[i+j-1]-sum[i-1]) 其中有几个细节,一是如果i+j-1==n,则当前先手只有唯一选择dp[i][j]=sum[n]-sum[i-1] ,二是若i+j-1>n,则不存在(i,j)状态下先手的任何状态,三是递推时要保证 (i+j,j) (i+j,j+1)如果算在转移中,一定要保证其为可行的先手状态。
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <vector> 5 #include <set> 6 #include <map> 7 #include <string> 8 #include <cstring> 9 #include <stack> 10 #include <queue> 11 #include <cmath> 12 #include <ctime> 13 #include <bitset> 14 #include <utility> 15 #include <assert.h> 16 using namespace std; 17 #define rank rankk 18 #define mp make_pair 19 #define pb push_back 20 #define xo(a,b) ((b)&1?(a):0) 21 #define tm tmp 22 //#define LL ll 23 typedef unsigned long long ull; 24 typedef pair<int,int> pii; 25 typedef long long ll; 26 typedef pair<ll,int> pli; 27 typedef pair<ll,ll> pll; 28 const int INF=0x3f3f3f3f; 29 const ll INFF=0x3f3f3f3f3f3f3f3fll; 30 const int MAX=2e6+5; 31 const ll MAXN=2e8; 32 const int MAX_N=MAX; 33 const double da=2e9+5.0; 34 const ll MOD=998244353; 35 //const long double pi=acos(-1.0); 36 //const double eps=0.00000001; 37 int gcd(int a,int b){return b?gcd(b,a%b):a;} 38 template<typename T>inline T abs(T a) {return a>0?a:-a;} 39 template<class T> inline 40 void read(T& num) { 41 bool start=false,neg=false; 42 char c; 43 num=0; 44 while((c=getchar())!=EOF) { 45 if(c=='-') start=neg=true; 46 else if(c>='0' && c<='9') { 47 start=true; 48 num=num*10+c-'0'; 49 } else if(start) break; 50 } 51 if(neg) num=-num; 52 } 53 inline ll powMM(ll a,ll b,ll M){ 54 ll ret=1; 55 a%=M; 56 // b%=M; 57 while (b){ 58 if (b&1) ret=ret*a%M; 59 b>>=1; 60 a=a*a%M; 61 } 62 return ret; 63 } 64 void open() 65 { 66 // freopen("1009.in","r",stdin); 67 freopen("out.txt","w",stdout); 68 } 69 ll dp[20005][150],sum[20005]; 70 int t,n,st; 71 int main() 72 { 73 scanf("%d",&t); 74 while(t--) 75 { 76 scanf("%d",&n); 77 for(int i=1;i<=n;i++)scanf("%lld",&sum[i]),sum[i]+=sum[i-1]; 78 for(int i=1;i<=n;i++) 79 { 80 st=(int)ceil((sqrt(1.0+8.0*i)-1.0)/2.0)+1; 81 for(int j=1;j<=st;j++) 82 dp[i][j]=INFF/2LL; 83 } 84 for(int i=n;i>=1;i--) 85 { 86 st=(int)ceil((sqrt(1.0+8.0*i)-1.0)/2.0)+1; 87 for(int j=st;j>=1;j--) 88 { 89 if(i+j-1==n) 90 dp[i][j]=sum[i+j-1]-sum[i-1];//选择唯一 91 else if(i+j-1>n) 92 dp[i][j]=INFF/2LL;//不存在 93 else 94 { 95 if(dp[i+j][j]==INFF/2LL&&dp[i+j][j]==INFF/2LL)dp[i][j]=sum[i+j-1]-sum[i-1]; 96 else if(dp[i+j][j+1]==INFF/2LL)dp[i][j]=-dp[i+j][j]+sum[i+j-1]-sum[i-1]; 97 else dp[i][j]=min(-dp[i+j][j]+sum[i+j-1]-sum[i-1],-dp[i+j][j+1]+sum[i+j-1]-sum[i-1]);//枚举后手的选择 98 } 99 } 100 } 101 if(n==1)printf("%lld\n",dp[1][1]); 102 else printf("%lld\n",max(dp[1][1],dp[1][2])); 103 } 104 }