題目連結:
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;
}