王の浮き沈み【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 C(intにある最初のjのタイプの数を分析できます。 i、int j);
要約すると、次の伝達方程式を得ることができます:sum [i] + =(dp [j-1] [0] * dp [ij] [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