51nod 1371 填数字 DP

本文介绍了一个关于在特定条件下填充格子的问题,并提供了一段C++代码实现。该问题要求在不超过2的限制下,计算所有可能的填充方案数量。通过动态规划的方法,文章详细展示了状态转移方程及其代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:有n行格子,第i(1<=i<=n)行有i个格子,每行格子是左对齐。现在要在每一个格子填入一个非负整数,最后使得每一行每一列的和都不超过2。
请计算有多少种方案,答案比较大,请输出对100,000,007(1e8+7)取余后的结果。

这题跟bzoj1801很像,基本上就是一道题了,但是注意这个地方可以一次放2,但是那题不行,所以我们还要改一下。
设f[i][j][k]表示做到了第i行,和为1的有j列,和为2的有k列,那么转移的话有7种,除了原来的6种(不知道这6种的移步),还新加了一种,就是一次加2的情况:
f[i][j][k]+=f[i1][j][k1](mkj+1) 然后把m都变为i就可以啦。
1A,爽啊。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
int n,m;
const int N=215;
const int mo=1e8+7;
typedef long long ll;
//int C[N][N]; 
ll f[N][N][N];
inline void add(ll &x,ll y)
{
    x=(x+y)%mo;
}
int main()
{
    //pre();
    scanf("%d",&n);
    memset(f,0,sizeof(f));
    f[0][0][0]=1;
    fo(i,1,n)
    {
        int m=i;
        fo(j,0,m)
        {
            fo(k,0,m-j)
            {
                f[i][j][k]=f[i-1][j][k];
                if (j>=1) (f[i][j][k]+=f[i-1][j-1][k]*(m-j-k+1))%=mo;  
                if (k>=1) (f[i][j][k]+=f[i-1][j+1][k-1]*(j+1))%=mo,(f[i][j][k]+=f[i-1][j][k-1]*(m-j-k+1))%=mo;  
                if (j>=2) (f[i][j][k]+=f[i-1][j-2][k]*(m-j-k+2)*(m-j-k+1)/2)%=mo;  
                if (k>=2) (f[i][j][k]+=f[i-1][j+2][k-2]*(j+2)*(j+1)/2)%=mo;  
                if (j>=1&&k>=1) (f[i][j][k]+=f[i-1][j][k-1]*(m-j-k+1)*j)%=mo; 
            }   
        }
    }
    ll ans=0;
    fo(j,0,n)
    fo(k,0,n-j)ans=(ans+1ll*f[n][j][k])%mo;
    printf("%lld\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值