简略题意:Bob和孩子玩游戏,孩子先手,每次他们从数组的两端取数。孩子每次都会取左右中最大的数,Bob任取。问能否让孩子获胜,且两人的分数差尽可能小。
说来惭愧,这题我不会,但是很多人过了,即使是折半枚举复杂度也还是很高,那就爆搜之后剪枝吧。
区间的极大极小值可以区间DP预处理得到。
对于某个状态
(l,r,val)
,代表当前还能取
[l,r]
区间,Bob和孩子的差值为val。
mx[l][r]代表Bob和孩子取[l,r]区间的数能得到的最大差值
mi[l][r]代表Bob和孩子取[l,r]区间的数能得到的最小差值
1
.若当前处于
2
.若当前处于
3
.若当前处于
即使是这样也还是过不去
参考这份题解snowy_smile的博客,加上流氓性剪枝就能
或者直接设置一个递归次数上限,也能
0ms
过…
其实还是数据水的原因。
#include <bits/stdc++.h>
using namespace std;
const int N = 92;
int t;
int n;
int v[N];
int mx[N][N], mn[N][N];
void umax(int &x, int y) {
if(x < y) x = y;
}
void umin(int &x, int y) {
if(x > y) x = y;
}
int ans;
bool sign = 0;
int cnt = 0;
void dfs(int l, int r, int val) {
if(sign) return ;
cnt++;
if(cnt >= 100000) {
sign = 1;
return ;
}
if(l > r) {
ans = max(ans, val);
return ;
}
if(val + mx[l][r] <= ans) return ;
if(val + mn[l][r] >= 0) return ;
if(val + mx[l][r] < 0) {
ans = max(ans, val + mx[l][r]);
return ;
}
int tmp;
if(v[l] >= v[r]) tmp = v[l++];
else tmp = v[r--];
dfs(l, r-1, v[r] + val - tmp);
dfs(l+1, r, v[l] + val - tmp);
}
int main() {
while(scanf("%d", &n) != EOF) {
sign = 0;
cnt = 0;
for(int i = 1; i <= n; i++) scanf("%d", &v[i]);
memset(mx, -0x3f3f3f3f, sizeof mx);
memset(mn, 0x3f3f3f3f, sizeof mn);
for(int i = 1; i <= n + 1; i ++)
mn[i][i-1] = mx[i][i-1] = mn[i][i-2] = mx[i][i-2] = 0;
for(int l = n; l >= 1; l--) {
for(int r = l; r <= n; r++) {
int ll = l, rr = r;
int tmp = 0;
if(v[ll] >= v[rr]) tmp = v[ll++];
else tmp = v[rr--];
umax(mx[l][r], mx[ll][rr-1] + v[rr] - tmp);
umax(mx[l][r], mx[ll+1][rr] + v[ll] - tmp);
umin(mn[l][r], mn[ll+1][rr] + v[ll] - tmp);
umin(mn[l][r], mn[ll][rr-1] + v[rr] - tmp);
}
}
ans = -0x3f3f3f3f;
dfs(1, n, 0);
if(ans == -0x3f3f3f3f || ans >= 0) puts("The child will be unhappy...");
else cout<<-ans<<endl;
}
return 0;
}