您的位置:首页 > 其它

[反序表 DP] 51Nod 1020 逆序排列

2016-11-17 07:30 169 查看
反序表那一套理论

来自:http://blog.csdn.net/synapse7/article/details/17093245



1. 先介绍反序表的概念:
令bi(1<=i<=n)为位于i左边但是大于i的元素个数,就能得到排列a1,a2,...,an的反序表b1,b2,...,b3
比如说,排列
5 9 1 8 2 6 4 7 3
有反序表
2 3 6 4 0 2 2 1 0(在1左边且大于1的有2个,在2左边且大于2的有3个,……)
2. 关键结论:
由1知,第1个元素的反序数取值范围是[0,n-1],第i个元素的反序数取值范围是[0,n-i],最后一个元素的反序数只能是0

(注意,每个反序数可以在区间内任意取值而不用考虑其他反序数的值,也就是说反序数是相互独立的。理由是反序表的个数亦为n!,而排列和反序表是一一对应的关系。)

3.
不难发现,每一趟bubble sort ,都会将反序数大于0的元素的反序数减1。若经过k趟之后排好序,则说明反序表中最大值为k。

那么这道题就是DP反序表的和

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;

const int P=1e9+7;
int f[1005][20005];

int main(){
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
f[0][0]=1;
for (int k=1;k<=20000;k++) f[0][k]+=f[0][k-1];
for (int i=1;i<=1000;i++){
for (int k=0;k<=20000;k++){
if (k-i-1>=0)
(f[i][k]=f[i-1][k]+P-f[i-1][k-i-1])%=P;
else
f[i][k]=f[i-1][k];
}
for (int k=1;k<=20000;k++) (f[i][k]+=f[i][k-1])%=P;
}
int T,n,K;
scanf("%d",&T);
while (T--){
scanf("%d%d",&n,&K);
if (K==0)
printf("%d\n",f[n-1][0]);
else
printf("%d\n",(f[n-1][K]+P-f[n-1][K-1])%P);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: