【BZOJ 3503】【CQOI 2014】和谐矩阵

f[i][j]=1表示i这个位置对j这个位置有影响,有偶数个1表示有影响的数的和在模2的情况下为0,这样可以列出n*m个方程,用高斯消元法求出一组可行解即可。
有两点要注意:为了方便起见,可以用异或代替加,因为异或也满足交换律和结合律。还有就是如果出现无数组解,优先赋为1,因为答案要求不能全0。

#include<cmath>
#include<cstdio>
#include<vector>
#include <queue>
#include<cstring>
#include<iomanip>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1000000000
#define mod 1000000007
#define N 2000
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
int i,j,k,n,m,tot;
int a[N][N],res[N],d[10][10],id[100][100];
void Gauss(int n,int m)
{
    int i,j,k;
    fo(i,1,n)
        {
            j = i; while (!a[j][i] && j <= m) j++;
            if (j > n) continue;
            if (j != i) fo(k,i,m) swap(a[i][k],a[j][k]);
            fo(j,i+1,n)
                if (a[j][i]) fo(k,i,m) a[j][k] ^= a[i][k];
        }
    fd(i,n,1)
        {
            if (!a[i][i]) {res[i] = 1; continue;}
            fo(j,i+1,n)
                a[i][m] ^= (res[j] * a[i][j]);
            res[i] = a[i][m]; 
        }
}

int main()
{
    d[1][0] = 0; d[1][1] = 0;
    d[2][0] = 1; d[2][1] = 0;
    d[3][0] = -1; d[3][1] = 0;
    d[4][0] = 0; d[4][1] = 1;
    d[5][0] = 0; d[5][1] = -1;
    scanf("%d%d",&n,&m);
    fo(i,1,n)
        fo(j,1,m)
            id[i][j] = ++tot;
    fo(i,1,n)
        fo(j,1,m)
            fo(k,1,5)
                {
                    int p = id[i+d[k][0]][j+d[k][1]];
                    if (p) a[id[i][j]][p] = 1;
                }
    Gauss(tot,tot+1);
    tot = 0;
    fo(i,1,n)
        {
            cout<<res[++tot];
            fo(j,2,m) cout<<" "<<res[++tot];
            cout<<endl;
        }
    return 0;   
}

extra

本题还有更加快的做法,所以可见出题人之良心。
我们发现,当第一行的数确定时,后面n-1行的数都能通过贪心确定,现在的问题转变为如何求出一组可行的第一行。
第一行可行的充要条件是最后一行的数是满足要求的,(前面n-1行如果出现奇数都能通过后面一行调整,最后一行只能自己满足自己),也等价于(假设加入的)第n+1行全为0。
考虑到本题全部可以用异或来做,分析第一行数对第n+1行数的影响。对第一行的数分别赋值为2^i,这样这m个数之间不会产生影响。然后填满这(n+1)*m个格子,观察第n+1行哪些数不为0,表示第一行中某些数对这个数影响。同样列出n个方程,高斯消元即可。

#include<cmath>
#include<cstdio>
#include<vector>
#include <queue>
#include<cstring>
#include<iomanip>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1000000000
#define mod 1000000007
#define N 41
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
int n,m,i,j;
int a[N][N],res[N][N];
ll b[N][N];
void gauss()
{
    int i,j,k;
    fo(i,1,m)
        {
            j = i; while (!a[j][i] && j <= m) j++;
            if (j > m) continue;
            if (j != i) fo(k,i,m+1) swap(a[i][k],a[j][k]);
            fo(j,i+1,m)
                if (a[j][i]) fo(k,i,m+1) a[j][k] ^= a[i][k];
        }
    fd(i,m,1)
        {
            if (!a[i][i]) {res[1][i] = 1; continue;}
            fo(j,i+1,m)
                a[i][m+1] ^= (res[1][j] * a[i][j]);
            res[1][i] = a[i][m+1];
        }
}
int main()
{
    scanf("%d%d",&n,&m);
    fo(i,1,m) b[1][i] = (ll)1<<(i-1);
    fo(i,2,n+1)
        fo(j,1,m)
            b[i][j] =b[i-1][j-1] ^ b[i-1][j] ^ b[i-1][j+1] ^ b[i-2][j];
    fo(i,1,m)
        fo(j,1,m)
            a[i][j] = ((b[n+1][i])>>(j-1))&1;
    gauss();
    fo(i,1,m-1) printf("%d ",res[1][i]); printf("%d\n",res[1][m]);
    fo(i,2,n)
        {
            fo(j,1,m) res[i][j] =res[i-1][j-1] ^ res[i-1][j] ^ res[i-1][j+1] ^ res[i-2][j];
            fo(j,1,m-1) printf("%d ",res[i][j]); printf("%d\n",res[i][m]);
        }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值