方格填色

题面描述

给一个\(m\cdot n\)的方格,每个格子可以是黑色或者白色。要求左右相邻两格不能同为白色且相邻两列不能全为黑色。求满足条件的方案数.\(1\leq m \leq 5 , 1\leq n\leq 10^{18}\)

题解

因为\(m\)很小,所以可以每列每列的考虑,每列可以用状压来表示,黑色为1,白色为0,则两列\(i|j=2^m-1,且两列不为2^m-1\)
则可以写出dp方程转移
\(dp[i][st]=\sum_{j=0}^{2^m-1}[j|st==2^m-1]\cdot dp[i-1][j] (st!=2^m-1)\)
\(dp[i][st]=\sum_{j=0}^{2^m-2}dp[i-1][j] (st==2^m-1)\)
显然可以写成矩阵乘法形式

\[\begin{pmatrix} dp[i][0]\\ dp[i][1]\\ ···\\ dp[i][2^m-1]\\ \end{pmatrix}=\begin{pmatrix}\\ \\ \\ \\ \end{pmatrix}*\begin{pmatrix}dp[i-1][0]\\dp[i-1][1]\\···\\dp[i-1][2^m-1]\end{pmatrix}\]

所以只要预处理中间的矩阵就行
时间复杂度为\(O((2^m)^3\cdot logn)\)

点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#define ll long long 
using namespace std;
const int maxn=5e5+101;
const int MOD=1e9+7;
const int inf=2147483647;
ll read(){
    ll x=0,f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
    return x*f;
}
ll m,n,dp[101];
struct wzq{ll a[101][101];}T;
void init(){
    for(int i=0;i<(1<<m);i++){
        for(int j=0;j<(1<<m);j++){
            if(i!=(1<<m)-1){
                if((i|j)==(1<<m)-1)T.a[i][j]=1;
            }
            else if(j!=(1<<m)-1)T.a[i][j]=1;
        }
    }
}
wzq dot(wzq x,wzq y){
    wzq sum;
    for(int i=0;i<(1<<m);i++){
        for(int j=0;j<(1<<m);j++){
            sum.a[i][j]=0;
            for(int k=0;k<(1<<m);k++){
                (sum.a[i][j]+=x.a[i][k]*y.a[k][j]%MOD)%=MOD;
            }
        }
    }
    return sum;
}
wzq qpow(wzq x,ll y){
    wzq sum;
    for(int i=0;i<(1<<m);i++){
        for(int j=0;j<(1<<m);j++)sum.a[i][j]=(i==j);
    }
    while(y){
        if(y&1)sum=dot(sum,x);
        y>>=1;x=dot(x,x);
    }
    return sum;
}
int main(){
    m=read();n=read();init();
    for(int i=0;i<(1<<m);i++)dp[i]=1;
    T=qpow(T,n-1);
    ll ans=0;
    for(int i=0;i<(1<<m);i++){
        for(int j=0;j<(1<<m);j++)(ans+=T.a[i][j]*dp[j]%MOD)%=MOD;
    }
    printf("%lld",(ans%MOD+MOD)%MOD);
    return 0;
}
posted @ 2021-11-16 18:17  I_N_V  阅读(273)  评论(0编辑  收藏  举报