Description
对于一个数列{ai},如果有i<j且ai>aj,那么我们称ai与aj为一对逆序对数。若对于任意一个由1~n自然数组成的
数列,可以很容易求出有多少个逆序对数。那么逆序对数为k的这样自然数数列到底有多少个?
Input
第一行为两个整数n,k。
Output
写入一个整数,表示符合条件的数列个数,由于这个数可能很大,你只需输出该数对10000求余数后的结果。
Sample Input
4 1
Sample Output
3
HINT
下列3个数列逆序对数都为1;分别是1 2 4 3 ;1 3 2 4 ;2 1 3 4;
100%的数据 n<=1000,k<=1000
题解
注意到逆序对的话,我们只在乎他们的相对数值,而不是具体是多少。
我们定义状态$f[i][j]$表示长度为$i$的排列,逆序对个数为$j$的方案数,显然我们转移的时候,考虑的是第$i$个数放在哪。
值得注意的是,这个数显然比之前的所有数都要大。即,我将$i$放在$i-j$的位置上,我将新获得$j$个逆序对。
我们容易想到$O(n^3)$的转移:
$$f[i][j] = {\sum_{k = 0}^{min(i-1, j)} f[i-1][j-k]}$$
边界情况是$f[1][0] = 1$。
$TLE$怎么办?前缀和优化一下就好了。
1 //It is made by Awson on 2017.10.18 2 #include <set> 3 #include <map> 4 #include <cmath> 5 #include <ctime> 6 #include <stack> 7 #include <queue> 8 #include <vector> 9 #include <string> 10 #include <cstdio> 11 #include <cstdlib> 12 #include <cstring> 13 #include <iostream> 14 #include <algorithm> 15 #define LL long long 16 #define Min(a, b) ((a) < (b) ? (a) : (b)) 17 #define Max(a, b) ((a) > (b) ? (a) : (b)) 18 #define Abs(x) ((x) < 0 ? (-(x)) : (x)) 19 using namespace std; 20 const int N = 1000; 21 const int MOD = 10000; 22 23 int f[N+5][N+5], n, m; 24 int sum[N+5]; 25 26 void work() { 27 scanf("%d%d", &n, &m); f[1][0] = sum[0] = 1; 28 for (int i = 1; i <= m; i++) sum[i] = sum[i-1]+f[1][i]; 29 for (int i = 2; i <= n; i++) { 30 for (int j = 0; j <= m; j++) { 31 (f[i][j] += sum[j]) %= MOD; 32 if (Min(i-1, j) > 0) (f[i][j] -= sum[j-Min(i-1, j)-1]) %= MOD; 33 } 34 for (int j = 1; j <= m; j++) sum[j] = sum[j-1]+f[i][j]; 35 } 36 printf("%d\n", (f[n][m]+MOD)%MOD); 37 } 38 int main() { 39 work(); 40 return 0; 41 }