zoukankan      html  css  js  c++  java
  • 『Codeforces 1186E 』Vus the Cossack and a Field (性质+大力讨论)

    Description

    给出一个$n imes m$的$01$矩阵$A$。

    记矩阵$X$每一个元素取反以后的矩阵为$X'$,(每一个cell 都01倒置)

    定义对$n imes m$的矩阵$A$进行一次变幻操作,变幻后矩阵的大小是$2n imes 2m$的。

    具体来说,我们会把$A$复制一份到$A$的右下方,计算$A'$并放置在$A$的正右方和正下方。

    设连续操作$n$的结果是$f^n(A)$ 即 $f^n(A) = left{egin{matrix} f(f^{n-1}(A)) & (ngeq 2)\  egin{Bmatrix} A & A' \  A' & A  end{Bmatrix}  & (n=1)\A & (n = 0)end{matrix} ight.$

    设矩阵$L = f^{infty} (A)$ ,给出$Q$个询问,$x1,y1,x2,y2$,求出$L$中子矩阵的和。

    对于$100\%$的数据满足$1 leq n,m leq 10^3 , 1 leq Q leq 10^6 , 1 leq x1leq x2 leq 10^9 ,  1 leq y1leq y2 leq 10^9$

    Idea & Solution

    我们不妨对于每个矩阵整体考虑。设没有进行翻转运算的矩阵为$0$,否则为$1$

    必然是长这样的:$egin{matrix} 0 & 1 &  1& 0 & 1 & 0 & 0 & 1&  ...\  1 & 0 & 0 & 1 & 0 &1  & 1  & 0 &...\  1 & 0 & 0 & 1 & 0 &1  & 1  & 0 & ...\  0 & 1 &  1& 0 & 1 & 0 & 0 & 1&  ... \  &&&&...end{matrix}$

    我们会显然的发现第一个数字为$0$的序列都相同,第一个数字为$1$的序列都相同。

    而两个序列恰好取反,于是我们可以尝试寻找第一行的性质。

    如果我们从$0$开始编号,那么起始点就是$0$,其值为$0$.

    对于第1行的第$i$个数字,必然是某一次扩展后产生的,我们会发现,一次扩展会对第一行的宽度$ imes 2$

    所以,第$i$个数字是$01$是和$Highestbit(i)$相反的,所以我们可以归纳一下发现,对于第$1$行第$i$个元素如果二进制上的$1$的个数为偶数那么就是$0$否则就是$1$.

    同时我们会发现纵向和横向的情况一模一样,所以可以进一步推论,$countbit(x) + countbit(y)  $为偶数那么就是$0$否则就是$1$.

    我们可能会发现,对于二维前缀和上的一个矩阵,$0$的个数和$1$的个数大致相等,可以分$x , y$坐标的奇偶性讨论$4$种可能即可计算。

    最后使用二维前缀和求子矩阵和。

    复杂度是$O(nm + T)$

    # include<bits/stdc++.h>
    # define int long long
    using namespace std;
    const int N=1005;
    int s0[N][N],s1[N][N],a[N][N],b[N][N];
    int n,m,q;
    int count(int x) { int ret=0;while(x){if(x&1)ret++;x>>=1;}return ret;}
    pair<int,int> find(int x,int y) { return make_pair((x-1)/n,(y-1)/m);}
    int check(int x,int y) { return (count(x)+count(y))&1;}
    inline int read()
    {
        int X=0,w=0; char c=0;
        while(c<'0'||c>'9') {w|=c=='-';c=getchar();}
        while(c>='0'&&c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar();
        return w?-X:X;
    }
    void write(int x)
    {
        if (x>9) write(x/10);
        putchar('0'+x%10);
    }
    int solve(int x,int y)
    {
        if (x<=0 || y<=0) return 0;
        pair<int,int>tmp=find(x,y); int cx = tmp.first, cy = tmp.second;
        if ((cx&1) && (cy&1)) {
            int ret = ((cx*cy-1)>>1)*n*m,h=x-cx*n,w=y-cy*m;
            ret=ret+h*((cy-1)>>1)*m+w*((cx-1)>>1)*n;
            if (check(cx,cy)==0) ret+=s0[h][w]; else ret+=s1[h][w];
            if (cx>=1 && cy>=1) { if (check(cx-1,cy-1)==0) ret+=s0[n][m]; else ret+=s1[n][m]; }
            if (cx>=1) { if (check(cx-1,cy)==0) ret+=s0[n][w]; else ret+=s1[n][w]; }
            if (cy>=1) { if (check(cx,cy-1)==0) ret+=s0[h][m]; else ret+=s1[h][m]; }
            return ret;
        } else if ((cx&1) && !(cy&1)) {
            int ret = (cx*cy>>1)*n*m,h=x-cx*n,w=y-cy*m;
            ret=ret+h*(cy>>1)*m+w*((cx-1)>>1)*n;
            if (check(cx,cy)==0) ret+=s0[h][w]; else ret+=s1[h][w];
            if (cx>=1) { if (check(cx-1,cy)==0) ret+=s0[n][w]; else ret+=s1[n][w]; }
            return ret;
        } else if (!(cx&1) && (cy&1)) {
            int ret = (cx*cy>>1)*n*m,h=x-cx*n,w=y-cy*m;
            ret=ret+h*((cy-1)>>1)*m+w*(cx>>1)*n;
            if (check(cx,cy)==0) ret+=s0[h][w]; else ret+=s1[h][w];
            if (cy>=1) { if (check(cx,cy-1)==0) ret+=s0[h][m]; else ret+=s1[h][m]; }
            return ret;
        } else if (!(cx&1) && !(cy&1)) {
            int ret = (cx*cy>>1)*n*m,h=x-cx*n,w=y-cy*m;
            ret=ret+h*(cy>>1)*m+w*(cx>>1)*n;
            if (check(cx,cy)==0) ret+=s0[h][w]; else ret+=s1[h][w];
            return ret;
        }
    }
    signed main()
    {
        n=read();m=read();q=read();
        for (int i=1;i<=n;i++) {
            for (int j=1;j<=m;j++) {
                char c=0; while (c!='0'&&c!='1') c=getchar();
                a[i][j]=(c=='1'); b[i][j]=1-a[i][j];
            }
        }
        for (int i=1;i<=n;i++)
         for (int j=1;j<=m;j++)
          s0[i][j]=s0[i-1][j]+s0[i][j-1]-s0[i-1][j-1]+a[i][j],
          s1[i][j]=s1[i-1][j]+s1[i][j-1]-s1[i-1][j-1]+b[i][j];
        while (q--) {
            int x1=read(),y1=read(),x2=read(),y2=read(); 
            int ans = solve(x2,y2)-solve(x2,y1-1)-solve(x1-1,y2)+solve(x1-1,y1-1);
            write(ans); putchar('
    ');
        }
        return 0;
    }

     

  • 相关阅读:
    Kubernetes 集成研发笔记
    Rust 1.44.0 发布
    Rust 1.43.0 发布
    PAT 甲级 1108 Finding Average (20分)
    PAT 甲级 1107 Social Clusters (30分)(并查集)
    PAT 甲级 1106 Lowest Price in Supply Chain (25分) (bfs)
    PAT 甲级 1105 Spiral Matrix (25分)(螺旋矩阵,简单模拟)
    PAT 甲级 1104 Sum of Number Segments (20分)(有坑,int *int 可能会溢出)
    java 多线程 26 : 线程池
    OpenCV_Python —— (4)形态学操作
  • 原文地址:https://www.cnblogs.com/ljc20020730/p/11431852.html
Copyright © 2011-2022 走看看