zoukankan      html  css  js  c++  java
  • 【hdu6185】Covering(骨牌覆盖)

    2017ACM/ICPC广西邀请赛-重现赛1004Covering

    题意

    n*4的格子,用1*2和2*1的砖块覆盖。问方案数(mod 1e9+7)。(n不超过1e9)

    题解

    递推了个式子然后错位相减。
    f[n] =f[n-1]+4f[n-2]+2f[n-3]+3f[n-4]+2f[n-5]+2f[n-6]+..+(x%2?2:3)f[n-x]
    f[n-2]= f[n-3]+4f[n-4]+2f[n-5]+3f[n-6]+..+(x%2?2:3)f[n-x]
    f[n] =f[n-1]+5f[n-2]+ f[n-3]-f[n-4]
    再用矩阵快速幂。
    另外,这题可以先用暴力的dfs或者状态压缩dp求得前几项,然后套BM板子得出递推式。
    不过,官方题解的方法是状态压缩加矩阵快速幂优化:
    只考虑一列的状态,0表示没有被覆盖,1表示被覆盖了,只可能有0000,1111,1001,0110,1100,0011。
    dp[i][j]表示前i-1列覆盖满,第i列状态为j的方案数。考虑转移,然后a[i][j]==1就是状态i可以由状态j转移过来,那么就可以矩阵快速幂加速了。

    --
    51nod 上的骨牌覆盖 V2,类似。a数组可以dfs出来。

    代码

    typedef long long ll;
    typedef vector<ll> VI;
    typedef vector<VI> Mat;
    const ll mod=1000000007;
    Mat mul(Mat &a,Mat &b){
    	Mat c(SZ(a), VI(SZ(b[0])));
    	rep(i,0,SZ(a))rep(j,0,SZ(b[0]))rep(k,0,SZ(b))
    		c[i][j]=(c[i][j]+a[i][k]*b[k][j])%mod;
    	return c;
    }
    Mat qpow(Mat a,ll b){
    	Mat c(SZ(a), VI(SZ(a)));
    	rep(i,0,SZ(a))c[i][i]=1;
    	for(;b;b>>=1,a=mul(a,a))if(b&1)c=mul(c,a);
    	return c;
    }
    
    int main(){
    	Mat a(4,VI(4));
    	a[0]=VI{1,5,1,-1};
    	rep(i,0,3)a[i+1][i]=1;
    	ll n;
    	while(~scanf("%lld",&n)){
    		if(n==1)puts("1");
    		else if(n==2)puts("5");
    		else if(n==3)puts("11");
    		else if(n==4)puts("36");
    		else{
    			Mat c=qpow(a,n-4);
    			printf("%lld
    ",((c[0][0]*36+c[0][1]*11+c[0][2]*5+c[0][3])%mod+mod)%mod);
    		}
    	}
    	return 0;
    }
    

    状态压缩

    int main() {
    	Mat a(6,VI(6));
    	a[0]=VI{1,1,1,1,1,0};
    	a[1]=VI{1,0,0,0,0,0};
    	a[2]=VI{1,0,0,1,0,0};
    	a[3]=VI{1,0,1,0,0,0};
    	a[4]=VI{1,0,0,0,0,1};
    	a[5]=VI{0,0,0,0,1,0};
    	ll n;
    	while(~scanf("%lld",&n)){
    		printf("%lld
    ",qpow(a,n)[0][0]);
    	}
    	return 0;
    }
    

    骨牌覆盖 V2

    const int N=1<<5;
    int n,m;
    Mat a(N,VI(N));
    void dfs(int c,int pre,int cur){
    	if(c>n)return;
    	if(c==n){
    		++a[pre][cur];
    		return;
    	}
    	dfs(c+1,pre<<1,cur<<1|1);//竖着放
    	dfs(c+1,pre<<1|1,cur<<1);//不能放
    	dfs(c+2,pre<<2,cur<<2);//横着放
    }
    int main() {
    	while(~scanf("%d%d",&m,&n)){
    		rep(i,0,SZ(a))rep(j,0,SZ(a[i]))a[i][j]=0;
    		dfs(0,0,0);
    		printf("%lld
    ",qpow(a,m)[0][0]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    TPLINK TLWR710N设置详解
    hehe.....
    AS3写FTP登录过程
    QQ
    网页设计标准尺寸:
    女孩,你愿意做他的第几个女朋友
    監聽一個變量的值變化
    dispatchEvent
    10
    C#常用代码
  • 原文地址:https://www.cnblogs.com/flipped/p/7467931.html
Copyright © 2011-2022 走看看