洛谷P3857[TJOI2008]彩灯

线性基的应用

我们读入开关控制的灯后,将他转化为2进制数,比如OXOXOXOXOX->1010101010,实际上数组存的是十进制

> if (num[i][k]=='O') a[i]=(a[i]<<1) | 1;

> else a[i]=a[i]<<1;

通过以上两个操作,就将地图转化成了二进制数,那和线性基有什么关系呢?我们发现,将初始状态看成一个长度为n的二进制串,初始每一位都是0,开灯操作就相当于0->1,那么我们发现通过线性基的求解操作可以保证在最多的灯亮着的情况下,将冲突的操作抹去,最后我们会得到一个01串,根据乘法原理,有多少个1就有2^k种变化,我们发现最大要到2^60,所以我们用快速幂求解

代码

//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int mod=2008; 
int n,m;
char num[100][100];
long long int a[100]={0},b[100];
int fpow(int a,int b)
{
	int ans=1;
	for (;b;a=(a*a)%mod,b>>=1)
		if (b&1) ans=(ans*a)%mod; 
	return ans;
}
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++) scanf("%s",num[i]+1);
	for (int i=1;i<=m;i++)
		for (int k=1;k<=n;k++)
			if (num[i][k]=='O') a[i]=(a[i]<<1)|1;
				else a[i]=a[i]<<1+0;
	for (int i=1;i<=m;i++)
	for (int k=n;~k;k--)
	if (a[i]&(1LL<<k)) 
		if (!b[k]){b[k]=a[i];break;}
			else a[i]^=b[k];
	int ans=0;
	for (int i=n;~i;i--)
		if (b[i]) ans++;
	cout<<fpow(2,ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/acerandaker/article/details/80889099