CodeForces 1270I Xor on Figures

CodeForces 1270I Xor on Figures

https://codeforces.com/contest/1270/problem/I

有一个 \(2^k \times 2^k(1 \le k \le 9)\) 的网格,其中 \((i,j)\) 位置上的数字为 \(a_{i,j}(0 \le a_{i,j} < 2^{60})\) .

这个网格是循环的,即 \((i,2^k)\) 的右边是 \((i,1)\) , \((2^k,i)\) 的下面是 \((1,i)\)

有一个网格图(不一定联通) \(F\) ,它包含 \(t\) 个两两不同的格子(\((1 \le t \le \min\{99,4^k\})\)\(t\) 为奇数) \((x_1,y_1),(x_2,y_2),\cdots,(x_t,y_t)(1 \le x_i,y_i \le 2^k)\) .

一次操作可以选择一个格子 \((x,y)(1 \le x,y \le 2^k)\) 和一个数字 \(p\) ,然后令所有 \((x+x_i \mod 2^k,y+y_i \mod 2^k)(1\le i \le t)\) 上的数字异或 \(p\) .

问至少需要多少次操作令所有格子中的数 \(=0\) .若不存在,输出 \(-1\)

Tutorial

https://www.luogu.com.cn/problem/solution/CF1270I

定义新矩阵乘法 \(A \times B =C\) ,其中\(\sum\)表示异或和

\[C(x,y) = \sum_{a=0}^{2^k-1} \sum_{b=0}^{2^k-1} A(a,b)B(x-a \mod 2^k,y-b \mod 2^k) \]

则我们需要的就是找到是否存在这样一个矩阵 \(C\) ,满足 \(C \times F = A\) ,且 \(C\) 中非零数的位置最少.

假如我们可以找到 \(F\) 在新矩阵乘法意义下面的逆元.那么可以证明 \(C\) 是存在且唯一的.

考虑 \(F \times F\) 的形状,其中有贡献的位置是 \((x_i+x_j \mod 2^k,y_i+y_j \mod 2^k)(1 \le i,j \le t)\) 的形式.考虑若 \(i\not= j\) 那么 \((i,j),(j,i)\) 分别贡献一次后这个位置上的数就会变为 \(0\) .

所以最后 \(F \times F\) 的所有非零位置就是 \((2x_i \mod 2^k,2y_i \mod 2^k)\) .

那么 \(F^{2^k}\) 的所有非零位置就是 \((2^kx_i \mod 2^k,2^ky_i \mod 2^k)=(0,0)\) ,而由于 \(t\) 是奇数,所以总是有奇数个 \(1\) ,所以 \((0,0)\) 位置上最后为 \(1\) .而这相当于在新矩阵乘法意义下的单位矩阵 \(I\)

\[F^{2^k} = I \\ F^{2^k-1}=F^{-1} \]

\[C=A \times F^{-1} = A \times F^{2^k-1} = A \times \prod_{i=0}^{k-1} F^{2^i} \]

由于 \(F\) 中的非零位置只有 \(t\) 个,所以一次新矩阵乘法的复杂度是 \(O(4^kt)\) 的.

总时间复杂度 \(O(kt4^k)\)

Code

#include <cassert>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#define fi first
#define se second
using namespace std;
inline char nc()
{
    static char buf[100000],*l=buf,*r=buf;
    return l==r&&(r=(l=buf)+fread(buf,1,100000,stdin),l==r)?EOF:*l++;
}
template<class T> void read(T &x)
{
    x=0; int f=1,ch=nc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=nc();}
    while(ch>='0'&&ch<='9'){x=x*10-'0'+ch;ch=nc();}
    x*=f;
}
typedef long long ll;
typedef pair<int,int> pii;
const int maxk=9;
const int maxn=1<<maxk;
const int maxt=99;
int k;
int n;
int t;
ll a[2][maxn][maxn];
pii F[maxt];
inline int add(int x) {return x>=n?x-n:x;} 
inline int sub(int x) {return x<0?x+n:x;}
int main()
{
    // freopen("in.txt","r",stdin);
    read(k),n=1<<k;
    int cur=0;
    for(int i=0;i<n;++i) for(int j=0;j<n;++j)
    {
        read(a[cur][i][j]);
    }
    read(t);
    for(int i=0;i<t;++i)
    {
        read(F[i].fi),read(F[i].se);
    }
    for(int i=0;i<k;++i)
    {
        cur^=1;
        memset(a[cur],0,sizeof(a[cur]));
        for(int x=0;x<n;++x) for(int y=0;y<n;++y)
        {
            for(int j=0;j<t;++j)
            {
                a[cur][x][y]^=a[cur^1][sub(x-F[j].fi)][sub(y-F[j].se)];
            }
        }
        for(int j=0;j<t;++j)
        {
            F[j].fi=add(F[j].fi<<1);
            F[j].se=add(F[j].se<<1);            
        }
    }
    int an=0;
    for(int x=0;x<n;++x) for(int y=0;y<n;++y)
    {
        if(a[cur][x][y]) ++an;
    }
    printf("%d\n",an);
    return 0;
}
posted @ 2020-06-02 15:12  LJZ_C  阅读(158)  评论(2编辑  收藏  举报