http://acm.hdu.edu.cn/showproblem.php?pid=3664
求1~n的排列个数,使得逆序数(ai>i ) 为给定的k.
dp[i][j]表示前1~i的排列中,有j个数是逆序数的个数.
#include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <string> #include <queue> #include <vector> #include<set> #include <iostream> #include <algorithm> using namespace std; #define RD(x) scanf("%d",&x) #define RD2(x,y) scanf("%d%d",&x,&y) #define clr0(x) memset(x,0,sizeof(x)) typedef long long ll; const int INF=0x3f3f3f3f; const int maxn=100010; const int mod=1000000007; ll dp[1010][1010]; int main() { int i,j,n,k; for(i=1;i<=1000;i++) { dp[i][0]=1; dp[i][i]=0; for(j=1;j<i;j++) dp[i][j]=((j+1)*dp[i-1][j]+(i-j)*dp[i-1][j-1])%mod; } while(~scanf("%d%d",&n,&k)) printf("%lld\n",dp[n][k]); return 0; } //当i放在dp[i-1][j]的j个位置或就放在第i个位置时。比下标大的数(E数)不会增加 //当第i个数放到dp[i-1][j-1]的(i-1)-(j-1)个位置上时。E数会在dp[i-1][j-1]的基础上增加一个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].