The King’s Ups and Downs HDU - 4489 (递推dp+好题)

传送门

题意:给出一个n,然后使用1-n构造出波浪形数据,问能构造多少组?

题解:很难想到,首先考虑从小到大进行插队,当插入最后这个最大的数时,怎么能插入进入呢?除非这个数前面是高低,后面是低高的形式,那么就用dp[i][0]表示符合波浪形且最后是高低的形式,用dp[i][1]表示符合波浪形开头是低高的形式,然后我们就开始从i-1个人中选出j个人去当这个dp[j][0],选法一共有c[i-1][j]种,这种组合数可以采用数组递推的形式出来, 参考传送门,之后就可以写出递推方程式了,此时的总方案数是ans=dp[j][0]*dp[i-j-1]*c[i-1][j],(0<=j<=i-1)之后还得考虑dp[i][0]与dp[i][1]怎么办?是否平分这个ans,答案是是的,当i是偶数时,最后两个是高低和开头两个是低高正好平分总方案数,当i是奇数时,最后两个是高低和开头两个是低高也正好平分总方案数,最后输出时将1特判下即可。

附上代码:


#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

const int maxn=20+5;

ll dp[maxn][2],c[maxn][maxn];

void getc()
{
    for(int i=0;i<maxn;i++){
        c[i][0]=c[i][i]=1;
    }
    for(int i=2;i<maxn;i++){
        for(int j=1;j<i;j++){
            c[i][j]=c[i-1][j-1]+c[i-1][j];
        }
    }
}

void mt()
{
    dp[0][0]=dp[0][1]=dp[1][0]=dp[1][1]=1;
    for(int i=2;i<maxn;i++){
        ll ans=0;
        for(int j=0;j<i;j++){
            ans+=dp[j][0]*dp[i-j-1][1]*c[i-1][j];
        }
        dp[i][0]=dp[i][1]=ans/2;
    }
}

int main()
{
    getc();
    mt();
    int p;
    scanf("%d",&p);
    while(p--){
        int id,n;
        scanf("%d%d",&id,&n);
        if(n==1){
            printf("%d %d\n",id,1);
        }else{
            printf("%d %lld\n",id,dp[n][0]+dp[n][1]);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zhouzi2018/article/details/86509274