我是靠谱客的博主 怡然豆芽,最近开发中收集的这篇文章主要介绍51nod 1020 逆序排列 (DP_好题),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述


在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。
如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的结果就可以了。
Input
第1行:一个数T,表示后面用作输入测试的数的数量。(1 <= T <= 10000)
第2 - T + 1行:每行2个数n,k。中间用空格分隔。(2 <= n <= 1000, 0 <= k <= 20000)
Output
共T行,对应逆序排列的数量 Mod (10^9 + 7)
Input示例
1
4 3
Output示例
6


设f(n,k)表示n个数的排列中逆序数个数为k的排列数。

最大的数n可能会排在第n-i位,从而产生i个与n有关的逆序对,去掉n之后,剩下的n-1个数的排列有k-i个逆序对。所以,f(n,k)=求和(f(n-1,k-i))(0<=i<n)。
同理有f(n,k-1)=求和(f(n-1,k-1-i))(0<=i<n)。
两式相减,可得f(n,k)-f(n,k-1)=f(n-1,k)-f(n-1,k-n)。
递推公式为f(n,k)=f(n,k-1)+f(n-1,k)-f(n-1,k-n)。
然后动态规划可得。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
int f[1111][22222];
const int mod=1e9+7;
void init()
{
int i,j;
for(i=1;i<=1000;i++) f[i][0]=1;
for(i=2;i<=1000;i++) {
for(j=1;j<=i*(i-1)/2&&j<=20000;j++){
f[i][j]=(f[i][j-1]+f[i-1][j])%mod;
if(j-i>=0) f[i][j]=((f[i][j]-f[i-1][j-i])%mod+mod)%mod;
}
}
}
int main()
{
int t,i,j,n,m;
init();
scanf("%d",&t);
while(t--) {
scanf("%d%d",&n,&m);
printf("%dn",f[n][m]);
}
return 0;
}





最后

以上就是怡然豆芽为你收集整理的51nod 1020 逆序排列 (DP_好题)的全部内容,希望文章能够帮你解决51nod 1020 逆序排列 (DP_好题)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(64)

评论列表共有 0 条评论

立即
投稿
返回
顶部