The King’s Ups and Downs【dp,排列组合】

在题目中主要的思考是,如何确定第n个和前面的关系,我们首先考虑的是,n和前面n-1个的关系,我们在n个中将n个人从矮到高依次排序为1~n,而依照题意,我们在第i个位置插入n必须满足题目意思,又因为n为当前最高点,所以只能左边为高矮,右边为矮高,又因为在全部的排列组合中,只存在矮高和高矮的顺序,所以设dp[i][0]为高矮,dp[i][1]为矮高,dp[i][0]=dp[i][1]=sum[i]/2;又因为在前面j个为高矮的时候可以在总共的i个数中取i个,所以我们可以用排列组合的方法分析在i个中取前j个种类是多少 C(int i,int j);
综上所述,我们可以得到转移方程式:sum[i]+=(dp[j-1][0]*dp[i-j][1]*Cal(i-1,j-1));
代码如下:

#include<bits/stdc++.h>
using namespace std;
const double eps = 1e-5;
const double PI = acos(-1.0);
typedef long long ll;
ll dp[30][2];//dp[i][j]任意i个中排列为0状况的方法多少种
ll sum[30];//在第i个的时候有多少个方法
ll Cal(int a,int b)//a个中取b个的方法多少个,排列组合
{
    
    
    if(b==0)
        return 1;
    ll res=1;
    for(int i=0;i<b;i++)
        res*=(a-i);
    for(int i=1;i<=b;i++)
        res/=i;
    return res;
}
int main()
{
    
    
    dp[0][0]=dp[0][1]=1;
    dp[1][0]=dp[1][1]=1;
    sum[1]=1;
    for(int i=2;i<=20;i++)
    {
    
    
        sum[i]=0;
        for(int j=1;j<=i;j++)//在前面放j-1个
            sum[i]+=(dp[j-1][0]*dp[i-j][1]*Cal(i-1,j-1));
        dp[i][0]=dp[i][1]=sum[i]/2;//由对称性
    }
    int t;
    int d,k;
    cin>>t;
    while(t--)
    {
    
    
        cin>>d>>k;
        cout<<d<<" "<<sum[k];
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/malloch/article/details/108995358