Source: 2017 ACM/ICPC Asia Regional Shenyang Online
Problem: 给你n个不同价值的宝石,排成一排,两个人轮流拿,若前者拿了k个,后者只能拿k或k+1个,第一个人最开始只能拿1个或2个,他要使两人之差最大,第二个人要使两人之差最小,两个人都是最优的拿法,问其结果。
Idea: DP。 由于k最大取值约为 sqrt(n∗2.0) ,所以可以将 O(n∗n∗2) 的复杂度优化到 O(n∗sqrt(n∗2)∗2) ,空间优化用到了取模的技巧。
Code:
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define CLR(A, X) memset(A, X, sizeof(A))
#define bitcount(X) __builtin_popcountll(X)
typedef long long LL;
typedef pair<int, int> PII;
const double eps = 1e-10;
const int MOD = 255;
const auto INF = 0x3f3f3f3f;
int dcmp(double x) { if(fabs(x) < eps) return 0; return x<0?-1:1; }
const int MAXN = 2e4+5;
int sum[MAXN], dp[2][256][256];
int main() {
int X, n;
scanf("%d", &X);
while(X--) {
CLR(dp, 0);
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &sum[i]);
sum[i] += sum[i-1];
}
int k = sqrt(n*2.0)+1;
for(int i = n; i >= 1; i--) {
for(int j = 1; j<=k && i+j-1<=n; j++) {
int u = i&MOD, v = (i+j)&MOD, d = sum[i+j-1]-sum[i-1];
int &d0 = dp[0][u][j], &d1 = dp[1][u][j];
d0 = dp[1][v][j]+d;
d1 = dp[0][v][j]-d;
if(i+j <= n) {
v = (v+1)&MOD, d += sum[i+j]-sum[i+j-1];
d0 = max(d0, dp[1][v][j+1]+d);
d1 = min(d1, dp[0][v][j+1]-d);
}
}
}
printf("%d\n", dp[0][1][1]);
}
return 0;
}