求逆序对:关于逆序对的DP(和归并没半毛关系)
1ff
我们说(i,j)是a1,a2,…,aN的一个逆序对当且仅当i<j且ai>a j。例如2,4,1,3,5的逆序对有3个,分别为(1,3),(2,3),(2,4)。现在已知N和K,求1…N的所有特定排列,这些排列的逆序对的数量恰好为K。输出这些特定排列的数量。
例如N=5,K=3的时候,满足条件的排列有15个,它们是: 1,2,5,4,3 1,3,4,5,2 1,3,5,2,4 1,4,2,5,3 1,4,3,2,5 1,5,2,3,4 2,1,4,5,3 2,1,5,3,4 2,3,1,5,4 2,3,4,1,5 2,4,1,3,5 3,1,2,5,4 3,1,4,2,5 3,2,1,4,5 4,1,2,3,5
输入输出格式 Input/output
输入格式:
输入第一行有两个整数N和K。(N≤100,K≤N*(N-1)/2) 输出格式: 将1…N的逆序对数量为K的特定排列的数量输出。为了避免高精度计算,请将结果mod 10000以后再输出!
输入输出样例 Sample input/output
样例测试点#1
输出样例:
15 构造f[i,j]表示(1..i)的全排列中,逆序对为j个的排列共有几个 我们首先手动模拟打表一下 f[1,0]=1 f[2,0]=1 f[3,0]=1 f[4,0]=1 f[2,1]=1 f[3,1]=2 f[4,1]=3 f[3,2]=2 f[4,2]=5 f[3,3]=1 f[4,3]=6 f[4,4]=5 f[4,5]=3 f[4,6]=1 表中有很多性质 比如:i的全排列中逆序对的个数是0..i*(i-1)/2:其实这是因为i的全排列中总共有i*(i-1)/2个数对,当这些数对全都是逆序对的时候,就得到了逆序对的最大值, 再比如:对于一个i,他的f[i,j]是关于f[i,i*(i-1)/4]呈现中心对称的(f[4,2]和f[4,4]、f[4,1]和f[4,5]、f[4,0]和f[4,6]关于f[4,3]对称):其实这是因为数对总数为i*(i-1)/2,而一个数对要么是逆序对要么是顺序对,那么我们求i的全排列中逆序对个数有j个, 等价于求i的全排列中顺序对有i*(i-1)/2-j个,显而易见,对于N的全排列 顺序对有K个这样的排列个数,和逆序对有K个这样的排列个数,是相等的于是我们有了f[i,j]=f[i, i*(i-1)/2-j]于是对称中心就是f[i,i*(i-1)/4]; 最后一个重要的性质也就是我们的DP状态转移方程就是: if i>j then f[i,j]:=sum{f[i-1,0],f[i-1,1],f[i-1,2].....f[i-1,j]} else f[i,j]:=sum{f[i-1,j],f[i-1,j-1],f[i-1,j-2].....f[i-1,j-i+1]} 当i>j的时候,我们枚举i的全排列的第一位的数字,如果是1,那么就要求剩下i-1个数中有j个全排列,如果是2,要求剩下i-1个数中有i-2个全排列,依次类推,得到了第一个方程 当i<=j的时候,由于i的全排列中最大的数字是i,所以把i放到第一位上,由第一位最多能能产生i-1个逆序对,把1放到第一位上能产生0个逆序对,所以i-1-1+1=i-1,这时的f[i,j]就要由f[i-1,j]开始算上他自己,总共i-1项的和。 AC代码: var f:array[1..100,-1..10000]of longint; var i,j,n,k:longint; begin read(n,k); fillchar(f,sizeof(f),0); f[1,0]:=1;f[1,1]:=0; f[2,0]:=1;f[2,1]:=1;//初始化 for i:=3 to n do begin for j:=0 to i*(i-1)div 4 do//从0计算到对称中心 if j<i then//第一种方式转移 f[i,j]:=(f[i,j-1]+f[i-1,j]) mod 10000//因为f[i,j]里面统计的是类似于前缀和的一个东西,f[i,j]只比f[i,j-1]多了f[i-1,j]这一项 else //第二种方式转移 f[i,j]:=(f[i,j-1]+f[i-1,j]-f[i-1,j-i])mod 10000;//这时求和的项数确定了,就是i-1项,于是f[i,j]比f[i,j-1]多了f[i-1,j]这一项,少了f[i-1,j-i]这一项 for j:=i*(i-1)div 4 +1 to i*(i-1) div 2 do//对称的把剩下的一半copy完 f[i,j]:=(f[i,i*(i-1)div 2 -j])mod 10000;//这里可以不用mod10000 end; writeln((f[n,k]+10000)mod 10000);//防坑输出,因为有的时候,a、b都是正数,但是a mod b布吉岛怎么是负数了。详见P2267,这道题 end.//如果你得了40分,那么用这样一个防坑输出法,你会惊奇的发现你AC啦 |
逆序对的dp
最新推荐文章于 2024-06-29 18:07:53 发布