您的位置:首页 > 其它

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

2017-03-14 10:32 411 查看
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

,res

;
ll b

;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  高斯消元法