【51Nod 1142】棋子遍历棋盘 矩阵快速幂+插头DP

原题走这里
从数据范围可以看出是矩阵快速幂优化

由于这种插头DP各行之间的转移是十(yi)分(mu)相(yi)似(yang)的。
我们可以用矩阵来描述d[i][m][1…S]到d[i+1][m][1…S]的转移。
算出每一个d[i][m][1…S]对每一个d[i+1][m][1…S]的贡献,储存在矩阵里。
做一次矩阵乘法就相当于完成了一行的转移,快速幂即可。
但是最后一步由于插头dp最后一格有特殊转移,矩阵快速幂只能做到m-1行,所以最后一行要特殊处理。

就是这样,感觉好玄学啊

代码如下:

#include 
#define LL long long
#define MOD 1000000007
using namespace std;
LL n,m,H[2500],s,S,d[2][2500];//S横截线的状态数 
map IH;
struct Matrix
{
    LL a[25][25];
    inline friend Matrix operator*(const Matrix &m1,const Matrix &m2)
    {
        Matrix m3;
        for(int i=0;ifor(int j=0;jfor(int k=0;kreturn m3;
    }
    Matrix()
    {
        memset(a,0,sizeof(a));
    }
}M;
void getHash(int k,int x,int y)
{
    if(y<0||y>m-k+1)return;
    if(k==m+1)IH[x]=s,H[s++]=x;
    getHash(k+1,x<<2,y);
    getHash(k+1,x<<2|2,y-1);
    getHash(k+1,x<<2|3,y+1);
}
void dp()
{
    for(int j=0,cur=0;j1)
    {
        memset(d[cur^1],0,sizeof(d[cur^1]));
        for(int k=0;kint temp=d[cur][k];
            if(!temp)continue;
            int t=H[k],x=t>>(j<<1)&3,y=t>>((j+1)<<1)&3;
            if(x==0&&y==0)
            {
                d[cur^1][IH[H[k]^(2<<(j<<1))^(3<<((j+1)<<1))]]+=temp;
            }
            if(x==3&&y==2)
            {
                d[cur^1][IH[H[k]^(3<<(j<<1))^(2<<((j+1)<<1))]]+=temp;
            }
            if(x+y==2||x+y==3)
            {
                d[cur^1][k]+=temp;
                d[cur^1][IH[H[k]^((x|y)<<(j<<1))^((x|y)<<((j+1)<<1))]]+=temp; 
            }
            if(x==2&&y==2)
            {
                for(int ii=j+2,jj=0;ii<=m;ii++)
                {
                    if((t>>(ii<<1)&3)==2)jj++;
                    if((t>>(ii<<1)&3)==3)jj--;
                    if(jj<0)
                    {
                        d[cur^1][IH[H[k]^(2<<(j<<1))^(2<<((j+1)<<1))^(1<<(ii<<1))]]+=temp;
                        break;
                    }
                }
            }
            if(x==3&&y==3)
            {
                for(int ii=j-1,jj=0;ii>=0;ii--)
                {
                    if((t>>(ii<<1)&3)==2)jj++;
                    if((t>>(ii<<1)&3)==3)jj--;
                    if(jj>0)
                    {
                        d[cur^1][IH[H[k]^(3<<(j<<1))^(3<<((j+1)<<1))^(1<<(ii<<1))]]+=temp;
                        break;
                    }
                }
            }
        }
    }
}
void getM()
{
    for(;H[S]<(1<<(m<<1));S++);
    for(int i=0;imemset(d,0,sizeof(d));
        d[0][IH[H[i]<<2]]=1;
        dp();
        for(int j=0;j1][j];
    }
}
Matrix qpow(Matrix x,int y)
{
    Matrix ans,temp=x;
    for(int i=0;i1;
    for(;y;y>>=1)
    {
        if(y&1)ans=ans*temp;
        temp=temp*temp;
    }
    return ans;
}
void laststep()
{
    memset(d,0,sizeof(d));
    for(int i=0;i0][IH[H[i]<<2]]=M.a[0][i];
    dp(); 
}
int main()
{
    cin>>n>>m;
    getHash(0,0,0);//状态处理 
    getM();//求转移矩阵 
    M=qpow(M,n-1);//矩阵快速幂 
    laststep();//最后一步递推 
    cout<<2*d[!(m&1)][IH[14<<((m-1)<<1)]]%MOD<return 0;
}

你可能感兴趣的:(【51Nod 1142】棋子遍历棋盘 矩阵快速幂+插头DP)