计数dp-hdu-3664-Permutation Counting

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=3664

题目意思:

求1~n的排列个数,使得逆序数(ai>i ) 为给定的k.

解题思路:

计数dp.

dp[i][j]表示前1~i的排列中,有j个数是逆序数的个数.dp[i][j]=(j+1)*dp[i-1][j]+(i-j)*dp[i-1][j-1].

考虑数i的放的位置,显然要想得到j个逆序数,i是大于前面的,所以只用考虑前面逆序数小于等于j的情况,而且放上这位最多只能增加一个逆序数。如果前面有j个逆序数,将这j个数与i交换,逆序数个数不变,第i个还可以放到第i个位置,此时为(j+1)*dp[i-1][j].当前面逆序数为j-1时,此时要构造一个逆序数,可以把前面的非逆序数与i交换,这样就多增加了一个逆序数,此时为(i-1-(j-1))*dp[i-1][j-1].

所以:dp[i][j]=(j+1)*dp[i-1][j]+(i-j)*dp[i-1][j-1].

代码:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#include<bitset>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define LL long long
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#define M 1000000007
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
#define Maxn 1100
ll dp[Maxn][Maxn];

int main()
{
    int n,k;

    memset(dp,0,sizeof(dp));
    dp[1][0]=1; //没有的时为顺序的
    for(int i=2;i<=1000;i++)
    {
        dp[i][0]=1;
        for(int j=1;j<i;j++) //两种情况
            dp[i][j]=((j+1)*dp[i-1][j]+(i-j)*dp[i-1][j-1])%M;
    }

    while(~scanf("%d%d",&n,&k))
    {
        if(k>=n)
        {
            printf("0\n");
            continue;
        }
        if(k==0)
        {
            printf("1\n");
            continue;
        }

        printf("%I64d\n",dp[n][k]);
    }
    return 0;
}


你可能感兴趣的:(动态规划)