HDU 5209 Magic Toy Brick

很好的一道dp题

首先可以推算出一行之中放n个最大m时的方案数为C(n+m-1,n)

设dp[n]表示n行的方案数 首先第一行 的第一个数应该是最小的 第一行的其他数是任意的 所以这一行取j个数时 的方案为C(n-1,j) * dp[n-j-1] (下面一行遵从同意的规则)

当时做的时候脑子抽了 写了个dfs以为是n²的 结果T了 调试了半天 才发那是n!的(>﹏<)  

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#define scnaf scanf
#define cahr char
#define bug puts("bugbugbug");
using namespace std;
typedef long long ll;
const int mod=1000000007;
const int maxn=101000+50;
const int maxe=200000;
ll fac[maxn], inv[maxn],ans;
int n,m,X[1005]={1},Y[1005]={1},a[1005];
ll powMod(ll a, ll b){
    ll ans=1;
    while(b)
    {
        if(b&1)
            ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans;
}
void init_c()
{
    int maxn=101000;
    fac[0]=1;
    for(int i=1; i<=maxn; i++)
        fac[i]=fac[i-1]*i%mod;
    inv[maxn]=powMod(fac[maxn],mod-2);
    for(int i=maxn-1; i>=0; i--)
        inv[i]=inv[i+1]*(i+1)%mod;
}
int c(int n,int m){
    return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
inline void RDF(int &ret) { //输入为负数
    char c;
    int sgn;
    while(c != '-' && (c < '0' || c > '9')) c = getchar();
    sgn = (c == '-') ? -1 : 1;
    ret = (c == '-') ? 0 : (c - '0');
    while(c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
    ret *= sgn;
}
inline void RD(int &ret) { //输入为整数
    char c;
    do {
        c = getchar();
    } while(c < '0' || c > '9');
    ret = c - '0';
    while((c = getchar()) >= '0' && c <= '9') {
        ret = ret * 10 + (c - '0');
    }
}
inline void OT(int a) { //输出为正数

    if(a >= 10) {
        OT(a / 10);
    }
    putchar(a % 10 + '0');
}
int T_T,test=1;
ll dp[1005];
void print(){
    putchar('C');putchar('a');putchar('s');putchar('e');putchar(' ');putchar('#');
    OT(test++); putchar(':');putchar(' '); OT(ans);putchar('\n');
}
int main()
{
    init_c();
    RD(T_T);
    while(T_T--){
        ans=0;
        RD(n);RD(m);
        for(int i=1;i<=n;i++){
            X[i]=c(i+m-1,i);
        }
        dp[0]=1;
        for(int i=1;i<=n;i++){
            dp[i]=0;
            for(int j=0;j<=i-1;j++)
            dp[i]=(dp[i]+c(i-1,j)*dp[i-1-j]%mod*X[j+1])%mod;
        }
        ans=dp[n];
       print();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值