HDU5766 Filling

Burnside+插頭DP
旋轉有四個羣 不動 旋轉 π2 π 3π2
顯然要染色在某置換下不動則每一塊結構相同
考慮分別計算
顯然 旋轉π2 與旋轉 3π2 答案相同

我們只需要考慮旋轉π2 的情況
此時將n*n的格子分成[n+12] *[n+12] 的四塊
2[n+12] 次枚舉左邊界
然後利用插頭DP求解出相應的方案數

對於180度即n*[n+12] 的插頭DP

注意合併狀態的時候的處理和狀態之間的有效轉移

我居然調試了一天。。

#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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章