逆序对
jzoj 2014
题目大意:
有一个长为n的序列(由1,2,3,……n组成),问经过某种调整之后,有k个逆序对(即在前面的一个数大于后面的一个数这样的对)的种数,有多组数据,以0 0结尾
样例输入
3 0
3 1
3 2
3 3
4 2
4 10
13 23
18 80
0 0
样例输出
1
2
2
1
5
0
46936280
184348859235088
数据范围限制
1 <= 数据组数 <=100, 1 <= n <= 50, 0 <= k <= 1500。
解题思路:
首先设f[i][j]f[i][j]f[i][j]为前iii个字符有jjj对逆序对的种数,然后因为插入的地方不同,且不同地方增加的逆序对也不同,所以得出:f[i][j]=∑k=0min(i−1,j)f[i−1][j−k]f[i][j]=\sum_{k=0}^{min(i-1,j)}f[i-1][j-k]f[i][j]=k=0∑min(i−1,j)f[i−1][j−k]
注:取min值是因为当kkk大于jjj时j−kj-kj−k会小于0
其次看到样例,我们可以发现数据是十分大的,所以要用高精,因为时间内存的限制,所以我们要压位
代码:
#include<cstdio>
#define min(x,y) (x)<(y)?(x):(y)
using namespace std;
int x,y,f[51][1501][11];
int main()
{f[1][0][1]=1;for (int i=2;i<=50;++i)//第几个数for (int j=0;j<=1500;++j)//有多少个逆序对for (int k=0;k<=(min(i-1,j));++k)//在哪里插入for (int c=1;c<=10;++c)//高精{f[i][j][c]+=f[i-1][j-k][c];//累加f[i][j][c+1]+=f[i][j][c]/1000000000;//压位f[i][j][c]%=1000000000;}scanf("%d %d",&x,&y);while (x!=0||y!=0){int k=10;while (!f[x][y][k]&&k>1) k--;//去零printf("%d",f[x][y][k]);//输出for (int i=k-1;i>0;--i)printf("%0*d",9,f[x][y][i]);//后面的要保持前导0putchar(10);//换行scanf("%d %d",&x,&y);} return 0;
}