题目:
在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。
如2 4 3 1中,2 1,4 3,4 1,3 1是逆序,逆序数是4。
1-n的全排列中,逆序数最小为0(正序),最大为n*(n-1) / 2(倒序)
给出2个数n和k,求1-n的全排列中,逆序数为k的排列有多少种?
例如:n = 4 k = 3。
1 2 3 4的排列中逆序为3的共有6个,分别是:
1 4 3 2
2 3 4 1
2 4 1 3
3 1 4 2
3 2 1 4
4 1 2 3
由于逆序排列的数量非常大,因此只需计算并输出该数 Mod 10^9 + 7的结果就可以了。
思路:dp,dp[i][j]表示前i个数形成j个逆序对的方案数,dp[i][j]=sigma(dp[i-1][j-i+1].....dp[i-1][j]).根据 i 这个最大的数放的位置来确定转移方程,可以用前缀和优化。
#include <bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int t,n,m;
int dp[1003][20003],sum[20003];
const int N=1000;
const int M=20000;
int main()
{
dp[1][0]=1;
for(int i=2;i<=N;i++)
{
sum[0]=1;
for(int j=1;j<=M;j++)
sum[j]=(sum[j-1]+dp[i-1][j])%mod;
for(int j=0;j<=M;j++)
dp[i][j]=((sum[j]-sum[max(0,j-i+1)]+mod)%mod+dp[i-1][max(0,j-i+1)])%mod;
}
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
printf("%d\n",dp[n][m]);
}
return 0;
}