51nod 1371 DP

有n行格子,第i(1<=i<=n)行有i个格子,每行格子是左对齐。现在要在每一个格子填入一个非负整数,最后使得每一行每一列的和都不超过2。

请计算有多少种方案,答案比较大,请输出对100,000,007(1e8+7)取余后的结果。

下图是n=4的时候格子的摆放。


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;

}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值