您的位置:首页 > 其它

51nod 1020 逆序排列——dp

2017-08-27 20:17 204 查看
在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。 如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
———————————————————————————
这道题就是道简单dp
我们记f【i】【j】i 的全排列中逆序数为j的数量
f【i】【j】=f【i-1】【k】 max(0,j-i+1)<=k<=j
因为你插入 i 这个数进入 i-1 的全排列中 你插入位置后面的数的逆序对全部+1
然后就解决问题辣
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int mod=1e9+7;
int read(){
int ans=0,f=1,c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
return ans*f;
}
int f[1007][20007],s[20007];
void prepare(){
f[1][0]=1;
for(int i=2;i<=1000;i++){
s[0]=f[i-1][0];
for(int j=1;j<=20000;j++) s[j]=(s[j-1]+f[i-1][j])%mod;
for(int j=0;j<=20000;j++){
int l=max(0,j-i+1),r=j;
if(l-1>=0) f[i][j]=(s[r]-s[l-1])%mod;
else f[i][j]=s[r];
}
}
}
int T,n,k;
int main(){
prepare();
T=read(); while(T--) n=read(),k=read(),printf("%d\n",(f
[k]+mod)%mod);
return 0;
}
View Code

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: