Description
RHL最近迷上一个小游戏:Flip it。游戏的规则很简单,在一个N*M的格子上,有一些格子是黑色,有一些是白色
。每选择一个格子按一次,格子以及周围边相邻的格子都会翻转颜色(边相邻指至少与该格子有一条公共边的格子
),黑变白,白变黑。RHL希望把所有格子都变成白色的。不幸的是,有一些格子坏掉了,无法被按下。这时,它 可以完成游戏吗?
Input
第一行一个整数T,表示T组数据。 每组数据开始于三个整数n,m,k,分别表示格子的高度和宽度、坏掉格子的个数。接下来的n行,每行一个长度m的
字符串,表示格子状态为’B’或’W’。最后k行,每行两个整数Xi,Yi(1≤Xi≤n,1≤Yi≤m),表示坏掉的格子。
n,m,k<=256,T<=10
Output
对于每组数据,先输出一行Case #i: (1≤i≤T) 如果可以成功,输出YES,否则输出NO。
Sample Input
2
3 3 0
WBW
BBB
WBW
3 3 2
WBW
BBB
WBW
2 2
3 2
Sample Output
Case #1:
YES
Case #2:
NO
题解
真的很经典的东西…
要记住
首先对于每个点,我们都可以列出一条异或方程
于是这就是一个有 n 2 n^2 n2个未知数, n 2 n^2 n2个方程的方程组
高斯消元过不去…
注意到是四连通,如果我们能确定第一行,显然第二行的填法是唯一的
同理,第三,第四,第五行直到第n行都是唯一的…
如此,我们可以推出每个点用第一行的点表示的异或组
然后用最后一行的点列异或方程
哦…有删去的点
那我们可以发现,这个点的异或方程解出来一定是0
那么暴力让周围四个点的异或和等于我这个点需要的次数即可
于是同样列 k k k个方程
高斯消元判一下有无解即可
此时只有 m m m个未知数和 n + k n+k n+k个方程,可以通过
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#include<iostream>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int stack[20];
inline void write(LL x)
{
if(x<0){putchar('-');x=-x;}
if(!x){putchar('0');return;}
int top=0;
while(x)stack[++top]=x%10,x/=10;
while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(LL x){write(x);putchar('\n');}
const int MAXN=260;
const int ux[4]={-1,0,1,0};
const int uy[4]={0,-1,0,1};
const int dx[4]={-1,-1,-1,-2};
const int dy[4]={0,-1,1,0};
bitset<MAXN> bit[MAXN][MAXN];
bitset<MAXN> rw[2*MAXN];
int n,m,num[MAXN][MAXN],tot,K;
bool gauss(int n,int m)
{
for(int i=1;i<=n;i++)
{
int u=-1;
for(int j=i;j<=n;j++)if(rw[j][i]==1){u=j;break;}
if(u==-1)continue;
swap(rw[u],rw[i]);
for(int j=i+1;j<=n;j++)
if(rw[j][i])rw[j]^=rw[i];
}
for(int i=1;i<=n;i++)
{
bool tf=false;
for(int j=1;j<=m;j++)if(rw[i][j]){tf=true;break;}
if(!tf&&rw[i][m+1])return false;
}
return true;
}
bool vis[MAXN][MAXN];
char ch[MAXN][MAXN];
bool in(int x,int y){return x>=1&&x<=n&&y>=1&&y<=m;}
int main()
{
// freopen("4171.in","r",stdin);
// freopen("4171.out","w",stdout);
int tt=0;
int T=read();while(T--)
{
memset(num,0,sizeof(num));
for(int i=1;i<=tot;i++)rw[i].reset();
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)bit[i][j].reset();
n=read();m=read();K=read();
for(int i=1;i<=n;i++)scanf("%s",ch[i]+1);
for(int i=1;i<=m;i++)bit[1][i][i]=1;
for(int i=2;i<=n;i++)for(int j=1;j<=m;j++)
{
for(int k=0;k<=3;k++)
if(in(i+dx[k],j+dy[k]))
{
int x=i+dx[k],y=j+dy[k];
bit[i][j]^=bit[x][y];num[i][j]^=num[x][y];
}
num[i][j]^=(ch[i-1][j]=='B');
// printf("%d %d\n",i,j);
// for(int k=1;k<=m;k++)cout<<bit[i][j][k];
// puts("");
// printf("%d\n",num[i][j]);
}
tot=0;
for(int i=1;i<=m;i++)
{
tot++;int g=num[n][i];
rw[tot]=bit[n][i];
if(in(n,i-1))
{
g^=num[n][i-1];
rw[tot]^=bit[n][i-1];
}
if(in(n,i+1))
{
g^=num[n][i+1];
rw[tot]^=bit[n][i+1];
}
if(in(n-1,i))
{
g^=num[n-1][i];
rw[tot]^=bit[n-1][i];
}
g^=(ch[n][i]=='B');
rw[tot][m+1]=g;
// printf("CHECKER %d\n",i);
// for(int k=1;k<=m+1;k++)cout<<rw[tot][k];
// puts("");
}
for(int i=1;i<=K;i++)
{
int x=read(),y=read();
int g=0;tot++;
for(int k=0;k<=3;k++)
if(in(x+ux[k],y+uy[k]))
{
int u=x+ux[k],v=y+uy[k];
rw[tot]^=bit[u][v];g^=num[u][v];
}
g^=(ch[x][y]=='B');
rw[tot][m+1]=g;
}
printf("Case #%d:\n",++tt);
if(gauss(tot,m))puts("YES");
else puts("NO");
}
return 0;
}