【问题描述】
给出一个
N∗M
的方格棋盘,每个格子里有一盏灯和一个开关,开始的时候,所有的灯都是关着的。用
(x,y)
表示第
x
行,
【数据规模与约定】
对于
20%
的数据,有
1≤n×m≤20
;
对于
40%
的数据,有
1≤n×m≤200
;
对于
70%
的数据,有
1≤n,m≤150
;
对于
100%
的数据,有
1≤n,m≤600
。
【题解】
显然我们可以看出,开关的处理就是异或嘛,然后就可以对于每一个节点按不按开关设成一个变量,然后暴力列方程高斯消元就可以了。这样复杂度的话是
O((n∗m)3)
的,即使使用
bitset
优化也是过不了的啊。
既然无法减少计算的复杂度,就看能不能削减方程数量。
我们知道,对于下面这样一个情况
具体地,我们设每一个点的左数一格,上数两格作为其的 X 格子,那么我们就能确定这个点了。
显然,有一些节点是不存在
我们实际上在做什么呢?对于每一个 8 号节点,我们相当于都是已经使用掉了这个节点的方程。因此若是有一些节点,这些节点无法作为别的节点的
代码如下
#include <bits/stdc++.h>
#define R register
#define LL long long
template<class TT>inline TT Max(R TT a,R TT b){return a<b?b:a;}
template<class TT>inline TT Min(R TT a,R TT b){return a<b?a:b;}
using namespace std;
template<class TT>inline void read(R TT &x){
x=0;R bool f=false;R char c=getchar();
for(;c<48||c>57;c=getchar())f|=(c=='-');
for(;c>47&&c<58;c=getchar())x=(x<<1)+(x<<3)+(c^48);
(f)&&(x=-x);
}
const int dx[]={-1,-2,-2,-1, 1, 2, 2, 1};
const int dy[]={-2,-1, 1, 2, 2, 1,-1,-2};
const int mod = 123456789;
inline LL qpow(R LL a,R LL b){
R LL r=1;
while(b){
if(b&1)r=r*a%mod;
b>>=1;
a=a*a%mod;
}
return r%mod;
}
const int maxn = 610;
const int maxm = maxn*3;
typedef bitset<maxm> BbB;
BbB a[maxn][maxn],tmp;
vector<BbB> S;
int n,m,ans;
inline bool in(R int x,R int y){
return -1<x&&x<n&&-1<y&&y<m;
}
inline void pre_work(){
for(R int i=0,lim=Min(2,n);i<lim;++i){
for(R int j=0;j<m;++j){
a[i][j][i*m+j]=1;
}
}
for(R int i=2;i<n;++i)a[i][0][(m<<1)+i-2]=1;
for(R int i=2;i<n;++i){
for(R int j=1,x,y;j<m;++j){
x=i-2;y=j-1;
a[i][j]=a[x][y];
for(R int k=0,xx,yy;k<8;++k){
xx=x+dx[k];
yy=y+dy[k];
if(in(xx,yy)&&(xx!=i||yy!=j))a[i][j]^=a[xx][yy];
}
}
}
for(R int i=n-3;i>=0;i--){
tmp=a[i][m-1];
for(R int j=0,x,y;j<8;++j){
x=i+dx[j];
y=m-1+dy[j];
if(in(x,y))tmp^=a[x][y];
}
S.push_back(tmp);
}
for(R int i=Max(n-2,0);i<n;++i){
for(R int j=0;j<m;++j){
tmp=a[i][j];
for(R int k=0,x,y;k<8;++k){
x=i+dx[k];y=j+dy[k];
if(in(x,y))tmp^=a[x][y];
}
S.push_back(tmp);
}
}
}
inline void get_ans(){
R int lim=S.size(),cnt=0;
for(R int i=0,j;i<lim;++i){
for(j=cnt;j<lim&&!S[j][i];++j);
if(j==lim)ans++;
else{
swap(S[cnt++],S[j]);
for(j=cnt;j<lim;++j){
if(S[j][i])S[j]^=S[cnt-1];
}
}
}
}
int main(){
read(n);read(m);
pre_work();
get_ans();
printf("%lld\n",qpow(2,ans)%mod);
return 0;
}