【BZOJ 3503】【CQOI 2014】和谐矩阵
2017-03-14 10:32
411 查看
f[i][j]=1表示i这个位置对j这个位置有影响,有偶数个1表示有影响的数的和在模2的情况下为0,这样可以列出n*m个方程,用高斯消元法求出一组可行解即可。
有两点要注意:为了方便起见,可以用异或代替加,因为异或也满足交换律和结合律。还有就是如果出现无数组解,优先赋为1,因为答案要求不能全0。
我们发现,当第一行的数确定时,后面n-1行的数都能通过贪心确定,现在的问题转变为如何求出一组可行的第一行。
第一行可行的充要条件是最后一行的数是满足要求的,(前面n-1行如果出现奇数都能通过后面一行调整,最后一行只能自己满足自己),也等价于(假设加入的)第n+1行全为0。
考虑到本题全部可以用异或来做,分析第一行数对第n+1行数的影响。对第一行的数分别赋值为2^i,这样这m个数之间不会产生影响。然后填满这(n+1)*m个格子,观察第n+1行哪些数不为0,表示第一行中某些数对这个数影响。同样列出n个方程,高斯消元即可。
有两点要注意:为了方便起见,可以用异或代替加,因为异或也满足交换律和结合律。还有就是如果出现无数组解,优先赋为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; }
相关文章推荐
- BZOJ 3503: [Cqoi2014]和谐矩阵( 高斯消元 )
- [BZOJ3503]-[CQOI2014]和谐矩阵-高斯消元
- BZOJ_3503_[Cqoi2014]和谐矩阵_高斯消元
- 【高斯消元】BZOJ3503 [Cqoi2014]和谐矩阵
- bzoj3503【CQOI2014】和谐矩阵
- BZOJ3503 [Cqoi2014]和谐矩阵
- BZOJ3503: [Cqoi2014]和谐矩阵
- bzoj3503 [Cqoi2014]和谐矩阵(高斯消元)
- [BZOJ3503][CQOI2014]和谐矩阵
- BZOJ 3503: [Cqoi2014]和谐矩阵(高斯消元)
- BZOJ3503: [Cqoi2014]和谐矩阵 解题报告
- 【BZOJ】【3503】【CQOI2014】和谐矩阵
- 【BZOJ3503】【Cqoi2014】和谐矩阵 高斯消元,解异或方程组
- BZOJ 3503 [CQOI2014]和谐矩阵
- BZOJ 3503([Cqoi2014]和谐矩阵-gauss消元)
- [bzoj3503] [Cqoi2014]和谐矩阵
- [BZOJ 3503][Cqoi 2014]和谐矩阵
- 【BZOJ 3503】 [Cqoi2014]和谐矩阵|高斯消元|xor方程组
- BZOJ 3503 CQOI 2014 和谐矩阵 高斯消元
- bzoj 3503: [Cqoi2014]和谐矩阵(高斯消元)