NKOJ 排列 [DP]

NKOJ 排列 [递推]

问题描述

将自然数 1 到 n 任意排列,然后在排列的每两个数之间根据他们的大小关系插入“>”和“<”。 例如:对于 1..5 的一个排列:3 2 4 1 5,可得到:3 > 2 < 4 > 1 < 5,其中有两个“>”和 2 个“<” 。 现在给出自然数 n,问在自然数 1..n 的所有排列中,有多少个排列恰好有 k 个“<”。 请你解答这个问题。

输入格式

包含多组数据。第一行一个整数 T,表示有 T 组数据。
每组数据的占一行,包含两个整数 n 和 k,它们之间用一个空格分开。

输出格式

共 T 行,每组数据输出一行,每行一个整数,表示对应输入的排列数,这个数如果很大,则需要 输出 mod 1000000007 的结果。

解法

f [ i ] [ j ] 表示从1到 i j < 的方案数

在每一个 < 后面 或 开头插入 i + 1 f [ i 1 ] [ j ] ( j + 1 )

在每一个 > 后面 或 末尾插入 i + 1 (多一个 < ): f [ i 1 ] [ j 1 ] ( i j )

得到方程: f [ i ] [ j ] = f [ i 1 ] [ j ] ( j + 1 ) + f [ i 1 ] [ j 1 ] ( i j )

代码

#include<iostream>
#include<cstdio>
#define M 1000000007
#define ll long long
using namespace std;
ll f[1010][1010];
int main(){
    ll t;scanf("%lld",&t);
    for(ll i=0;i<=1000;i++)f[i][0]=1;
    for(ll i=1;i<=1000;i++)
        for(ll j=1;j<=1000;j++)
            f[i][j]=(f[i-1][j-1]*(i-j)+f[i-1][j]*(j+1))%M;
    for(ll i=1;i<=t;i++){
        ll n,k;scanf("%lld%lld",&n,&k);
        printf("%lld\n",f[n][k]);
    }
    return 0;
} 

猜你喜欢

转载自blog.csdn.net/arliastark/article/details/80621430