zoukankan      html  css  js  c++  java
  • CF1439A2 Binary Table (Hard Version) 题解

    题意分析

    给出一个 $n×m$ 的只由 $0,1$ 构成的矩阵,每次可以将一个 $2×2$ 的子矩阵中的 $3$ 个数取反。要求将整个矩阵的所有元素变为 $0$ ,并且操作次数不能超过 $nm$ 次。要求给出操作次数和具体方案。

    思路分析

    由于每次只能修改一个 $2×2$ 的子矩阵中的 $3$ 个数,想到考虑每个 $2×2$ 的子矩阵的情况,尝试把每个 $2×2$ 的子矩阵单独处理,看看合不合法。

    显然可以根据 $1$ 的个数划分为五种情况,对每种情况分别考虑。

    具体实现

    情况一: $0$ 个 $1$

    显然不用处理,需要 $0$ 次操作。

    情况二: $3$ 个 $1$

    将 $3$ 个 $1$ 取反即可,需要 $1$ 次操作。

    情况三: $2$ 个 $1$

    将 $2$ 个 $0$ 和 $1$ 个 $1$ 取反,可以变为情况二,接着处理,需要 $2$ 次操作。

    情况四: $1$ 个 $1$

    将 $2$ 个 $0$ 和 $1$ 个 $1$ 取反,可以变为情况三,接着处理,需要 $3$ 次操作。

    情况五: $4$ 个 $1$

    将 $3$ 个 $1$ 取反,可以变为情况一,接着处理,需要 $4$ 次操作。

    可以发现,所有情况最多只需要 $4$ 次操作,刚好与子矩阵的元素数目相等,因此一定可以满足操作次数不大于 $nm$ 。

    若 $n$ 或 $m$ 为奇数,不能刚好划分为 $2×2$ 的子矩阵,就先把一行全部变成 $0$ ,然后再处理剩下的即可。注意后面的处理不能影响到前面已经处理过的元素。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    using namespace std;
    const int N=200,M=3e4+100;
    int T,n,m,ans;
    int dx[4]={0,1,0,1},dy[4]={0,0,1,1};
    int x1[M],x2[M],x3[M],y1[M],y2[M],y3[M],a[N][N];
    string s;
    int ano(int x)
    {
        return ((x-1)^1)+1;
    }//找相邻的数,其中奇数较小,偶数较大
    void solve1(int i,int j)
    {
        ans++;
        for(int k=0,x=i+dx[k],y=j+dy[k];k<4;k++,x=i+dx[k],y=j+dy[k])
            if(!a[x][y])
            {
                if(!x1[ans])
                    a[x][y]=1,x1[ans]=x,y1[ans]=y;
                else
                    if(!x2[ans])
                        a[x][y]=1,x2[ans]=x,y2[ans]=y;//取反 2 个 0
            }
            else
                if(!x3[ans])
                    a[x][y]=0,x3[ans]=x,y3[ans]=y;//取反 1 个 1
    }//取反 2 个 0 和 1 个 1
    void solve2(int i,int j)
    {
        ans++;
        for(int k=0,x=i+dx[k],y=j+dy[k];k<4;k++,x=i+dx[k],y=j+dy[k])
            if(a[x][y])
                if(!x1[ans])
                    a[x][y]=0,x1[ans]=x,y1[ans]=y;
                else
                    if(!x2[ans])
                        a[x][y]=0,x2[ans]=x,y2[ans]=y;
                    else
                        if(!x3[ans])
                            a[x][y]=0,x3[ans]=x,y3[ans]=y;
    }//取反 3 个 1
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d",&n,&m);ans=0;
            for(int i=1;i<=n*m;i++)
                x1[i]=x2[i]=x3[i]=y1[i]=y2[i]=y3[i]=0;
            for(int i=1;i<=n;i++)
            {
                cin>>s;
                for(int j=1;j<=m;j++)
                    a[i][j]=s[j-1]-'0';
            }
            if(n&1)// n 为奇数,处理第 n 行
                for(int i=1;i<=m;i++)
                    if(a[n][i])
                        a[n][i]=0,a[n-1][i]^=1,a[n-1][i==m?i-1:i+1]^=1,x1[++ans]=n,x2[ans]=n-1,x3[ans]=n-1,y1[ans]=i,y2[ans]=i,y3[ans]=i==m?i-1:i+1;
            if(m&1)// m 为奇数,处理第 m 列
                for(int i=1;i<=n;i++)
                    if(a[i][m])
                        if(i<m)
                            a[i][m]=0,a[i][m-1]^=1,a[i==1?i+1:i-1][m-1]^=1,x1[++ans]=i,x2[ans]=i,x3[ans]=i==1?i+1:i-1,y1[ans]=m,y2[ans]=m-1,y3[ans]=m-1;
                        else
                            a[n][m-1]=0,a[n-1][m]^=1,a[n-1][m-1]^=1,x1[++ans]=n,x2[ans]=n-1,x3[ans]=n-1,y1[ans]=m,y2[ans]=m,y3[ans]=m-1;
            for(int i=1;i<=n;i+=2)
                for(int j=1;j<=m;j+=2)
                {
                    if(a[i][j]+a[i+1][j]+a[i][j+1]+a[i+1][j+1]==4)
                        solve2(i,j);
                    if(a[i][j]+a[i+1][j]+a[i][j+1]+a[i+1][j+1]==1)
                        solve1(i,j);
                    if(a[i][j]+a[i+1][j]+a[i][j+1]+a[i+1][j+1]==2)
                        solve1(i,j);
                    if(a[i][j]+a[i+1][j]+a[i][j+1]+a[i+1][j+1]==3)
                        solve2(i,j);
                }//划分处理,根据处理先后按顺序
            printf("%d
    ",ans);
            for(int i=1;i<=ans;i++)
                printf("%d %d %d %d %d %d
    ",x1[i],y1[i],x2[i],y2[i],x3[i],y3[i]);
        }
        return 0;
    }

    我甚至没想出 $3nm$ 的怎么做

  • 相关阅读:
    关于这个 blog
    P6499 [COCI2016-2017#2] Burza 题解
    CF1172F Nauuo and Bug 题解
    CF1479D Odd Mineral Resource 题解
    CF1442E Black, White and Grey Tree 题解
    CF1442D Sum 题解
    CF1025D Recovering BST 题解
    CF1056E Check Transcription 题解
    CF1025F Disjoint Triangles 题解
    红包算法的PHP实现
  • 原文地址:https://www.cnblogs.com/TEoS/p/14004239.html
Copyright © 2011-2022 走看看