原题: http://acm.zjnu.edu.cn/CLanguage/showproblem?problem_id=2283
题意:
n*n的01矩阵,你可以无限次翻转一行或者一列,可以最多翻转k(k<=n)次一个点。问是否可以全部翻转成0。
解析:
k<=n说明至少有一行不会被翻转单个点,或者k=n时每行翻转一个点。那么枚举每一行为那一行,将其他行与之对比(可以翻转后再对比),不同的数量就是需要翻转单个点的数量。因为有列翻转,所以全部行都一样后可以全部变成0。
每一行一个点的情况也很简单,第一行枚举每个位置翻转,判断其他行是否只翻转一个点后与之相同。
不同点的个数用bitset维护。
#include<bits/stdc++.h>
using namespace std;
char x[1002];
bitset<1002>B[1002];
int main(){
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
B[i].reset();
scanf("%s",x+1);
for(int j=1;j<=n;j++){
if(x[j]=='x')B[i].set(j);
}
}
if(k==n){
for(int i=1;i<=n;i++){
int can=1;
if(i-1)B[1].flip(i-1);
B[1].flip(i);
for(int j=2;j<=n;j++){
B[0]=B[1]^B[j];
int sub=B[0].count();
if(sub!=1&&n-sub!=1){can=0;break;}
}
if(can)return 0*printf("DA\n");
}
B[1].flip(n);
}
int ans=1e9;
for(int i=1;i<=n;i++){
int sum=0;
for(int j=1;j<=n;j++){
if(i==j)continue;
B[0]=B[i]^B[j];
int sub=B[0].count();
sub=min(sub,n-sub);
sum+=sub;
}
ans=min(ans,sum);
}
if(ans<=k)printf("DA\n");
else printf("NE\n");
}