bzoj3503【CQOI2014】和谐矩阵

3503: [Cqoi2014]和谐矩阵

Time Limit: 10 Sec   Memory Limit: 128 MBSec   Special Judge
Submit: 841   Solved: 370
[ Submit][ Status][ Discuss]

Description

我们称一个由0和1组成的矩阵是和谐的,当且仅当每个元素都有偶数个相邻的1。一个元素相邻的元素包括它本
身,及他上下左右的4个元素(如果存在)。
给定矩阵的行数和列数,请计算并输出一个和谐的矩阵。注意:所有元素为0的矩阵是不允许的。

Input

输入一行,包含两个空格分隔的整数m和n,分别表示矩阵的行数和列数。

Output


输出包含m行,每行n个空格分隔整数(0或1),为所求矩阵。测试数据保证有解。

Sample Input

4 4

Sample Output

0 1 0 0
1 1 1 0
0 0 0 1
1 1 0 1

数据范围
1 <=m, n <=40

HINT

Source

鸣谢Ljcc提供Spj




高斯消元的应用

方法一:对于每一个元素,它与上下左右的和模2等于0,所以可以得到一个模2意义下的方程,即异或方程。每一个元素都能得到一个方程,总共有n*m个方程,又有n*m个未知数,高斯消元求值即可。


#include
#include
#include
#include
#include
#include
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
using namespace std;
int n,m,cnt;
int id[50][50],a[2000][2000],b[2000],ans[2000];
int dx[5]={0,0,0,1,-1},dy[5]={0,1,-1,0,0};
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void gauss(int n)
{
	F(i,1,n)
	{
		bool flag=false;
		F(j,i,n) if (a[j][i])
		{
			F(k,1,n) swap(a[i][k],a[j][k]);
			flag=true;break;
		}
		if (!flag) continue;
		F(j,i+1,n) if (a[j][i]) F(k,i,n) a[j][k]^=a[i][k];
	}
	D(i,n,1)
	{
		ans[i]=a[i][i]?b[i]:1;
		if (ans[i]) F(j,1,i-1) if (a[j][i]) b[j]^=1;
	}
}
int main()
{
	n=read();m=read();
	F(i,1,n) F(j,1,m) id[i][j]=++cnt;
	F(i,1,n) F(j,1,m) F(k,0,4)
	{
		int t1=id[i][j],t2=id[i+dx[k]][j+dy[k]];
		if (t2) a[t1][t2]=1;
	}
	gauss(cnt);
	F(i,1,n)
	{
		F(j,1,m-1) printf("%d ",ans[id[i][j]]);
		printf("%d\n",ans[id[i][m]]);
	}
	return 0;
}


方法二:相比方法一而言,方法二的未知数的数量更少,高斯消元的复杂度更低。可以发现如果a[i][j]=a[i-1][j-1]^a[i-1][j]^a[i-1][j+1]^a[i-2][j],所以如果第一行确定,递推可得到所有的元素。而第一行的元素取值合理,当且仅当地推出第m+1行的元素都为0。于是又转化成异或方程组,依然用高斯消元。思路很巧妙。


#include
#include
#include
#include
#include
#include
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
using namespace std;
int n,m;
ll a[50][50],b[50][50],c[50][50];
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void gauss()
{
	F(i,1,m)
	{
		int t=i;
		while (t<=m&&!a[t][i]) t++;
		if (t>m) continue;
		F(j,1,m) swap(a[i][j],a[t][j]);
		F(j,i+1,m) if (a[j][i]) F(k,i,m) a[j][k]^=a[i][k];
	}
	D(i,m,1)
	{
		c[1][i]=a[i][i]?a[i][m+1]:1;
		if (c[1][i]) F(j,1,i-1) if (a[j][i]) a[j][m+1]^=1;
	}
}
int main()
{
	n=read();m=read();
	F(i,1,m) b[1][i]=(ll)1<<(i-1);
	F(i,2,n+1) F(j,1,m) b[i][j]=b[i-1][j-1]^b[i-1][j]^b[i-1][j+1]^b[i-2][j];
	F(i,1,m) F(j,1,m) a[i][j]=(b[n+1][i]>>(j-1))&1;
	gauss();
	F(i,2,n) F(j,1,m) c[i][j]=c[i-1][j-1]^c[i-1][j]^c[i-1][j+1]^c[i-2][j];
	F(i,1,n)
	{
		F(j,1,m-1) printf("%d ",c[i][j]);
		printf("%d\n",c[i][m]);
	}
	return 0;
}


你可能感兴趣的:(好题,高斯消元,OIer的狂欢)