CodeForces 1270I Xor on Figures

CodeForces 1270I Xor on Figures

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

有一个 (2^k imes 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)(1le i le t)) 上的数字异或 (p) .

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

Tutorial

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

定义新矩阵乘法 (A imes B =C) ,其中

[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 imes F = A) ,且 (C) 中非零数的位置最少.

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

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

所以最后 (F imes 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 imes F^{-1} = A imes F^{2^k-1} = A imes 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
",an);
    return 0;
}
原文地址:https://www.cnblogs.com/ljzalc1022/p/13031383.html