【问题描述】
Alice和Bob在玩一个游戏,游戏是在一个N*N的矩阵上进行的,每个格子上都有一个正整数。当轮到Alice/Bob时,他/她可以选择最后一列或最后一行,并将其删除,但必须保证选择的这一行或这一列所有数的和为偶数。如果他/她不能删除最后一行或最后一列,那么他/她就输了。两人都用最优策略来玩游戏,Alice先手,问Alice是否可以必胜?
【输入格式】
第一行:T,表示数据组数
对于每组数据的第一行:N
接下来N行,每行N个数,描述这个矩阵
【输出格式】
如果Alice必胜输出W,否则输出L
【输入样例】
2
2
2 4
6 8
3
5 4 2
1 5 9
7 3 8
【输出样例】
L
W
【数据规模】
100%数据满足 1<=N<=1000,1<=T<=5 保证每一行或每一列的和不会超过2*10^9
30%数据满足 1<=N<=5
50%数据满足 1<=N<=100
70%数据满足 1<=N<=500
【我的思路】
由于这题是模拟赛自己想出来的,又是第一次考这种类型的题目,就很有成就感,于是标签就多了“成就感” qwq,既然是自己想出来的,那就写简单一点了。
每次删最后一排或最后一列,用 bool类型 f(x,y) 表示 (1,1) 到 (x,y) 这个矩阵先手 能(1) 否 (0) 必胜。
如果f(x,y-1)=0,若最后一列可以删,就赢了,即f(x,y)=1;
同理f(x-1,y)=0,若最后一排可以删,就赢了,即f(x,y)=1;
若 前二者 都等于 1,那么 如果当前可以删,对手确定必胜;如果当前不能删,我方已经输了。
所以 这种情况无论如何必输。
怎么看最后一排(列)能不能删呢?
用二维前缀和维护就好了。
#include<bits/stdc++.h> using namespace std; long long a[1005][1005]; bool f[1005][1005]; int n,T; int main() {freopen("game.in","r",stdin); freopen("game.out","w",stdout); scanf("%d",&T); for(int iii=1;iii<=T;iii++) { scanf("%d",&n); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { scanf("%lld",&a[i][j]); a[i][j]=a[i-1][j]+a[i][j-1]-a[i-1][j-1]+a[i][j]; } memset(f,0,sizeof(f)); //printf("--------------------\n"); /* for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) printf("%lld ",a[i][j]); debug cout<<endl; } */ //printf("--------------------\n"); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { if(f[i-1][j]==0) if((a[i][j]-a[i-1][j])%2==0) {f[i][j]=1;continue;} if(f[i][j-1]==0) if((a[i][j]-a[i][j-1])%2==0) {f[i][j]=1;continue;} } if(f[n][n]) printf("W\n");else printf("L\n"); } return 0; }