點擊開啟連結
題目大意:
有長度為n的正數序列,兩個遊戲者A 和B輪流取,A先取。每次玩家可以選擇從序列左邊或右邊開始取一個或連續多個數字,問最終A最多可以比B大多少?
分析:
設f[l][r]表示對於區間[l,r]的序列,先取的人最多可以取的和。
那麼,可以選擇把[l,r]的所有數全部取光,或者只取一部分。
如果只取一部分,假設是[l,k]z這區間全部取,那麼總共可以得到的和為sum[l,k]+(sum[k+1,r]-f[k+1][r])
所以狀態轉移為:
f[l][r] = sum[l][r]-min{ min{f[l][k], f[k+1][r]} }, l<=k<r
#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>using namespace std;typedef long long int64;const int INF = 0x3f3f3f3f;int n, arr[110], sum[110];int f[110][110];int main(){ sum[0] = 0; while(~scanf("%d", &n) && n){ for(int i=1; i<=n; ++i){ scanf("%d", &arr[i]); sum[i] = sum[i-1] + arr[i]; } memset(f, 0, sizeof(f)); for(int i=1; i<=n; ++i) f[i][i] = arr[i]; for(int len=2; len<=n; ++len){ for(int l=1; l+len-1<=n; ++l){ int r = l+len-1; int tot = sum[r] - sum[l-1]; f[l][r] = tot; // 把[l, r]全部取 for(int k=l; k<r; ++k){ f[l][r] = max(f[l][r], tot-min(f[l][k], f[k+1][r])); //選擇取[l,k]或[k+1,r]的情況 } } } printf("%d\n", 2*f[1][n]-sum[n]); } return 0;}