Burnside+插頭DP
旋轉有四個羣 不動 旋轉
顯然要染色在某置換下不動則每一塊結構相同
考慮分別計算
顯然 旋轉
我們只需要考慮旋轉
此時將n*n的格子分成
然後利用插頭DP求解出相應的方案數
對於180度即n*
注意合併狀態的時候的處理和狀態之間的有效轉移
我居然調試了一天。。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
using namespace std;
char c;
inline void read(int&a)
{
a=0;do c=getchar();while(c<'0'||c>'9');
while(c<='9'&&c>='0')a=(a<<3)+(a<<1)+c-'0',c=getchar();
}
int M[101][101];
int f[2][5000001];
const
int Mod=1e9+7;
void Up(int &a,int b){a+=b;if(a>=Mod)a-=Mod;}
int Mul(int a,int b){return a*1ll*b%Mod;}
int Pow(int a,int x)
{
int res=1;
for(;x;x>>=1,a=a*1ll*a%Mod)
if(x&1)res=res*1ll*a%Mod;
return res;
}
int Way[1001],Sum[1001];
int T[20];
int main()
{
Sum[0]=Sum[1]=Way[0]=1;
for(int i=2;i<=40;i++)
Way[i]=Sum[i-2],Sum[i]=Sum[i-1]+Way[i];
for(int i=1;i<=40;i++)
Way[i]=Way[i-1]+Way[i];
int Ans=0;
int T=20;
for(int ci=1;ci<=T;ci++)
{
int N=ci;
Ans=0;
int n=N+1>>1;
for(int i=0;i<=n+1;i++)M[i][0]=M[n+1][i]=M[i][n+1]=M[0][i]=1;
int last=0,now=1;
//0
for(int i=1;i<=N;i++)
for(int j=1;j<=N;now^=1,last^=1,j++)
{
for(int S=0;S<(1<<N+1);S++)
f[now][S]=0;
if(i==1&&j==1)
{
f[now][(1<<N+1)-3]=1;
continue;
}
for(int S=0;S<(1<<N+1);S++)
if(f[last][S])
{
int front=S&(1<<j-1),up=S&1;
if(j==1)
front=up=1;
Up(f[now][(((S|1)^1)|((S>>j)&1)|(1<<j))^(1<<j)],f[last][S]);
if((!front)&&!up&&!((S>>j)&1))
Up(f[now][S|1|(1<<j)|(1<<j-1)],f[last][S]);
}
}
for(int i=0;i<(1<<N+1);i++)
Up(Ans,f[last][i]);
for(int L=0;L<(1<<n);L++)
{
for(int i=0;i<n;i++)
M[i+1][n-1]=M[i+1][n]=(L&(1<<i))?1:0;
int now=1,last=0;
for(int i=0;i<(1<<n+1);i++)f[last][i]=f[now][i]=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++,now^=1,last^=1)
{
for(int S=0;S<(1<<n+1);S++)f[now][S]=0;
if(i==1&&j==1)
{
f[now][(1<<n+1)-3]=1;
continue;
}
for(int S=0;S<(1<<n+1);S++)
if(f[last][S])
{
int front=S&(1<<j-1),up=S&1;
if(j==1)
{
front=1,up=1;
if(i>2&&M[i-2][n]==1&&!(S&1))
f[last][S]=0;
}
Up(f[now][(((S|up)^up)|((S>>j)&1)|(1<<j))^(1<<j)],f[last][S]);
if((!front)&&!up&&!((S>>j)&1))
{
if(j==n&&!(M[i][j]&&M[i-1][j]))
continue;
Up(f[now][S|1|(1<<j)|(1<<j-1)],f[last][S]);
}
}
}
}
int i=n+1;
for(int S=0;S<1<<(n+1);S++)
{
if(i>2&&M[i-2][n]==1&&!(S&1))
f[last][S]=0;
if(i>1&&M[i-1][n]&&!(S&(1<<n)))
f[last][S]=0;
}
// 90 270
if(!(N&1))
{
for(int S=0;S<(1<<n+1);S++)
if(f[last][S])
if((S>>n)^(L>>n-1))continue;
else
{
int j;
int Res=1;
for(int i=1;i<=n;i=j+1)
{
j=i;
if((1&(L>>j-1))||(1&(S>>j)))continue;
while(j+1<n&&!((1&(L>>j))||(1&(S>>j+1))))j++;
int cnt=j-i+1;
Res=Mul(Res,Way[cnt]);
}
Res=Mul(2,Res);
Up(Ans,Mul(Res,f[last][S]));
if(!((S>>n)&1))
{
Res=0;
int j;
int Res=1;
for(int i=1;i<=n;i=j+1)
{
j=i;
if((1&(L>>j-1))||(1&(S>>j)))continue;
while(j+1<n&&!(1&((L>>j))||(1&(S>>j+1))))j++;
int cnt=j-i+1;
Res=Mul(Res,Way[cnt]);
}
Res=Mul(2,Res);
Up(Ans,Mul(Res,f[last][S]));
}
}
}
else if(!((L>>n-1)&1))
{
for(int S=0;S<(1<<n+1);S++)
if(f[last][S]&&!((S>>n)&1))
{
int P=S>>1;
if(P&L)continue;
Up(Ans,Mul(2,f[last][S]));
}
}
}
//180
for(int i=1;i<=n;i++)
{
for(int j=1;j<=N;j++,now^=1,last^=1)
{
for(int S=0;S<(1<<N+1);S++)f[now][S]=0;
if(i==1&&j==1)
{
f[now][(1<<N+1)-3]=1;
continue;
}
for(int S=0;S<(1<<N+1);S++)
if(f[last][S])
{
int front=S&(1<<j-1),up=S&1;
if(j==1)front=1,up=1;
Up(f[now][(((S|up)^up)|((S>>j)&1)|(1<<j))^(1<<j)],f[last][S]);
if((!front)&&!up&&!((S>>j)&1))
Up(f[now][S|1|(1<<j)|(1<<j-1)],f[last][S]);
}
}
}
if(N&1)
{
for(int S=0;S<(1<<N+1);S++)
if(f[last][S])
{
int T=0;
for(int i=1;i<=N;i++)
if((S>>i)&1)
T|=1<<N-i+1;
if(((T|1)^1)&((S|1)^1))continue;
Up(Ans,f[last][S]);
}
}
else
{
for(int S=0;S<(1<<N+1);S++)
if(f[last][S])
{
int T=0;
for(int i=1;i<=N;i++)
if((S>>i)&1)T|=1<<N-i+1;
int Res=1,j;
for(int i=1;i<=n;i=j+1)
{
j=i;
if(((S>>j)&1)||((T>>j)&1))continue;
while(j+1<=n&&!(((S>>j+1)&1)||((T>>j+1)&1)))j++;
int cnt=j-i+1;
Res=Mul(Res,Way[cnt]);
}
Up(Ans,Mul(Res,f[last][S]));
if((!((T>>n)&1))&&!((S>>n)&1))
{
int Res=1,j;
for(int i=1;i<=n;i=j+1)
{
j=i;
if(((S>>j)&1)||((T>>j)&1))continue;
while(j+1<n&&!(((S>>j+1)&1)||((T>>j+1)&1)))j++;
int cnt=j-i+1;
Res=Mul(Res,Way[cnt]);
}
Up(Ans,Mul(Res,f[last][S]));
}
}
}
printf(", %d\n",Mul(Pow(4,Mod-2),Ans));
}
return 0;
}
然後我們可以打個表。。。mdzz