有n行格子,第i(1<=i<=n)行有i个格子,每行格子是左对齐。现在要在每一个格子填入一个非负整数,最后使得每一行每一列的和都不超过2。
请计算有多少种方案,答案比较大,请输出对100,000,007(1e8+7)取余后的结果。
下图是n=4的时候格子的摆放。
![](http://img.51nod.com/upload/000FBE7B/08D236C75ED7F1A10000000000000002.png)
Input
第1行:给出一个整数n (1<=n<=200)。
Output
对于每个测试用例,输出结果占一行。
Input示例
1
Output示例
3
官方题解:
DP题,状态dp[i][j][k]表示第i行填完之后有j列的和是1,k列的和是2。
然后加入第i+1行。
对第i+1行的最后一个格子进行分类讨论。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string.h>
#include<algorithm>
using namespace std;
#define ll __int64
#define mod 100000007
ll dp[205][205][205];//0的个数 1的个数
//
ll C[210][210];
void init()
{
C[0][0]=1ll;
C[1][0]=C[1][1]=1ll;
for(int i=2;i<=205;i++)
{
C[i][i]=C[i][0]=1ll;
for(int j=1;j<i;j++)
{
C[i][j]=C[i-1][j-1]+C[i-1][j];
C[i][j]%=mod;
}
}
}
int main()
{
int n;
// freopen("in.txt","r",stdin);
init();
while(scanf("%d",&n)!=EOF)
{
memset(dp,0,sizeof(dp));
dp[1][0][0]=dp[1][1][0]=dp[1][0][1]=1ll;
for(int i=1;i<n;i++)
{
for(int j=0;j<=i;j++)
{
for(int k=0;k<=(i-j);k++)
{
int col0=j;
int col1=k;
col0++;
for(int k1=0;k1<=min(col0,2);k1++)//放几个1在0
{
// cout<<"m "<<j<<" "<<k<<endl;
for(int k2=0;k2<=min(col0-k1,1);k2++)//放几个2
{
for(int k3=0;k3<=col1;k3++)//放几个1在1
{
// cout<<"r"<<endl;
if(k1+k3>2) break;
if(col0-k2+col1-k3>i+1) break;
if(k1+k3+2*k2>2) continue;
int t1=col1-k3+k1;
int t2=col0-k2-k1;
int t3=i+1-t1-t2;
// if(t1==0 && t2==0 ) cout<<t1<<" "<<t2<<" "<<t3<<endl;
// if(2*t3+t2>2) continue;
dp[i+1][col0-k2-k1][col1-k3+k1]+=dp[i][col0-1][col1]*C[col0][k1]%mod*C[col0][k2]%mod*C[col1][k3]%mod;
// if(t1==0 && t2==0) cout<<(col0-k2-k1)<<" "<<(col1-k3+k1)<<" "<<dp[i+1][col0-k2-k1][col1-k3+k1]<<" "<<(col0-1)<<" "<<col1<<" "<<dp[i][col0-1][col1]<<endl;
dp[i+1][col0-k2-k1][col1-k3+k1]%=mod;
}
}
}
}
}
}
ll ans=0;
for(int i=0;i<=n;i++)
for(int j=0;j<=(n-i);j++)
ans+=dp[n][i][j],ans%=mod;//cout<<i<<" "<<j<<" "<<dp[n][i][j]<<endl;
printf("%I64d\n",ans);
}
return 0;
}