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$ 的怎么做

  • 相关阅读:
    使用WCF实现消息推送
    T31P电子秤数据读取
    持续性任务代码的一些测试
    XP+Android手机DIY家庭视频点播系统-历时3周全力打造吊丝的幸福生活
    Android 上传文件到XP
    Android ListView的一个坑,你可掉进去过?
    无脑无负担网站架构-- Application Request Route的一些应用
    Android 一些注意
    懒人的ERP开发框架--2B&苦B程序员专用
    PHP Token(令牌)设计应用
  • 原文地址:https://www.cnblogs.com/TEoS/p/14004239.html
Copyright © 2011-2022 走看看