题目链接:http://nyoj.top/web/contest/problem/cid/13/num/B

题目:

用1*2的地砖,填满4*N的墙,有多少种方案。

题解:

状压dp,枚举每个状态的可能转移状态,再计算。

#include<bits/stdc++.h>
using namespace std;
const int mod=997;
const int maxn=1e6+10;
int a[maxn][16];
int main()
{
	a[1][0]=1;					//转移到第一列的时候,可能的方案为1。因为无法填入,所以只有0这一种状态 
	for(int i=2;i<1e6+5;i++)	//合法状态0 3 6 9 12 15 
	{
		a[i][0]=(a[i-1][0]+a[i-1][3]+a[i-1][9]+a[i-1][12]+a[i-1][15])%mod;
		a[i][3]=(a[i-1][0]+a[i-1][12])%mod;
		a[i][6]=(a[i-1][9])%mod;
		a[i][9]=(a[i-1][0]+a[i-1][6])%mod;
		a[i][12]=(a[i-1][0]+a[i-1][3])%mod;
		a[i][15]=(a[i-1][0])%mod;
	}
	int t;
	cin>>t;
	while(t--)
	{
		int n,m,k;
		cin>>n>>m>>k;
		int l=m-1,r=n-(k+m-1);
		printf("%d %d\n", a[l+1][0], a[r+1][0]); //输出下一列没溢出来的状态
	} 
	return 0;
} 

 

#include<bits/stdc++.h>
using namespace std;
long long dp[2][20];
const int mod=997;
int n=1000000,m=4;
int a[1000005];
void f()
{
	int total=1<<m,pre=0,now=1;
	memset(dp[now],0,sizeof(dp[now]));
	dp[now][0]=1;
	for(int i=0;i<n;i++)		//列 
	{
		for(int j=0;j<m;j++)	//行 
		{
			swap(now,pre);
			memset(dp[now],0,sizeof(dp[now]));
			for(int S=0;S<total;S++) 	//枚举状态
			{
				if( dp[pre][S] )
				{
					dp[now][S^(1<<j)]=(dp[now][S^(1<<j)]+dp[pre][S])%mod;
					if( j && S&(1<<(j-1)) && !(S&(1<<j)))
						dp[now][S^(1<<(j-1))]=(dp[now][S^(1<<(j-1))]+dp[pre][S])%mod;
				}
			}
		}
		a[i]=dp[now][0];
	}
}
int main()
{
	int t;
	cin>>t;
	f();
	while(t--)
	{
		int d,b,c;
        cin>>d>>b>>c;
        int x1=b-1;
        int x2=d-(b+c-1);
        
        cout<<a[x1-1]<<' ';
        cout<<a[x2-1]<<endl;
	}
}