题目链接:
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;
}
本文介绍了解决HDU 3664问题的一种动态规划方法,该问题要求计算1到n的排列数量,使逆序数等于给定值k。通过构建dp数组,利用递推公式dp[i][j]=(j+1)*dp[i-1][j]+(i-j)*dp[i-1][j-1],实现了高效求解。
611

被折叠的 条评论
为什么被折叠?



