P2599 取石子游戏
题目简述:
最右边的石子已经满足了先手必败时的条件,先手必败。
Case2:a_j<l_{i,j-1},\ a_j<r_{i,j-1}
此时有
Case3:a_j≥l_{i,j-1},\ a_j<r_{i,j-1}
此时有
- 若剩余石子大于
l_{i,j-1} ,后手只需要在右侧取相同数量的石子就可以循环回到 Case3。 - 若剩余石子等于
l_{i,j-1} ,后手只需要取完右端所有石子,触发a_{i-1}=l_{i,j-1} 的先手必败状态。 - 若剩余石子小于
l_{i,j-1} ,后者只需要取右端石子直至与左端相等,则回到 Case2。由于有a_j≥l_{i,j-1} ,所以先手取完时一定有a_j≥l_{i,j-1}≥a_{i-1} 。
如果先手取右侧:
- 若剩余石子大于
l_{i,j-1} ,后手只需要在左侧取石子直至比右端多一就可以回到 Case3。 - 若剩余石子等于
l_{i,j-1} ,后手只需要在左侧取石子直至比右端多一就可以回到 Case3。 - 若剩余石子小于
l_{i,j-1} ,后手只需要在左侧取石子直至与右端相等,则回到 Case2。
Case4:a_j≤l_{i,j-1},\ a_j>r_{i,j-1}
此时有
- 若剩余石子大于
r_{i,j-1} ,后手只需要在右侧取石子直至比左端多一就可以回到 Case4。 - 若剩余石子等于
r_{i,j-1} ,后手只需要在右侧取石子直至比左端多一就可以回到 Case4。 - 若剩余石子小于
r_{i,j-1} ,后者只需要取右端石子直至与左端相等,则回到 Case2。
如果先手取右侧:
- 若剩余石子大于
r_{i,j-1} ,后手只需要在左侧取相同数量的石子就可以循环回到 Case3。 - 若剩余石子等于
r_{i,j-1} ,后手只需要取完左端所有石子,触发a_{j}=r_{i,j-1} 的先手必败状态。 - 若剩余石子小于
r_{i,j-1} ,后者只需要取左端石子直至与右端相等,则回到 Case2。
Case5:a_j≥l_{i,j-1},\ a_j>r_{i,j-1}
此时有
- 若剩余石子小于
l_{i,j-1},r_{i,j-1} ,一定可以回到 Case2。 - 若剩余石子大于
l_{i,j-1},r_{i,j-1} ,一定可以回到 Case5。 - 若剩余石子等于
l_{i,j-1},r_{i,j-1} ,后手可以通过在另一堆取石子回到 Case4 或 Case3。
上面的五个 Case 对称过来就是其他的方案,方案类似不再赘述。最后只需要判断
Code:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<climits>
#include<algorithm>
#include<utility>
#define int long long
using namespace std;
const int MaxN=1003;
int lL[MaxN][MaxN], rR[MaxN][MaxN], a[MaxN];
inline int Read(){
int num = 0, op = 1;
char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') op = -1;
ch = getchar();
}
while(isdigit(ch)){
num = num * 10 + ch - '0';
ch = getchar();
}
return num * op;
}
signed main(){
int T = Read();
while(T--){
int n = Read();
for(int i=1;i<=n;++i)
a[i] = Read(), lL[i][i] = rR[i][i] = a[i];
for(int len=1; len<n; len++){
for(int l=1,r=l+len; r<=n; l++,r++){
int x, L, R;
x = a[r], L = lL[l][r-1], R = rR[l][r-1];
if(x == R) lL[l][r] = 0;
else if(x > R && x > L || x < R && x < L) lL[l][r] = x;
else if(x >= L && x < R) lL[l][r] = x + 1;
else if(x > R && x <= L) lL[l][r] = x - 1;
x = a[l], L = lL[l+1][r], R = rR[l+1][r];
if(x == L) rR[l][r] = 0;
else if(x > R && x > L || x < R && x < L) rR[l][r] = x;
else if(x > L && x <= R) rR[l][r] = x - 1;
else if(x >= R && x < L) rR[l][r] = x + 1;
}
}
if(a[1]==lL[2][n]) printf("0\n");
else printf("1\n");
}
return 0;
}