P7315 [COCI2018-2019#3] Sajam

· · 题解

由于本题原唯一题解是错误的贪心,现提供一种有正确性证明的方法。

给一个 n \times n01 矩阵,每次使一行或一列状态反转,问能否用若干次操作后使得最终矩阵的 1 的个数 \le k

本题关键条件为 k \le n,不运用此条件我们的贪心无从下手。

这里我们分成两类情况:

总时间复杂度 \mathcal O(\dfrac{n^3}{w})

int n,k;
bitset<1005>st[1005];
int main(){
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
        char s[1005];
        scanf("%s",s+1);
        for(int j=1;j<=n;j++)
            if(s[j]=='o')st[i][j]=1;
    }
    if(k==n){
        for(int i=1;i<=n;i++){
            st[1].flip(i);
            bool chk=false;
            for(int j=2;j<=n;j++){
                st[j]=st[1]^st[j];
                if(min(st[j].count(),n-st[j].count())>1){
                    chk=true;st[j]=st[1]^st[j];
                    break;
                }
                st[j]=st[1]^st[j];
            }
            if(!chk){
                puts("DA");
                return 0;
            }
            st[1].flip(i);
        }
    }
    for(int i=1;i<=n;i++){
        int sum=0;
        for(int j=1;j<=n;j++){
            if(i==j)continue;
            st[j]=st[j]^st[i];
            sum+=min(st[j].count(),n-st[j].count());
            st[j]=st[j]^st[i];
        }
        if(sum<=k){
            puts("DA");
            return 0;
        }
    }
    puts("NE");
    return 0;
}