题目描述
对于一个数列{ai},如果有i<j且ai>aj,那么我们称ai与aj为一对逆序对数。若对于任意一个由1~n自然数组成的数列,可以很容易求出有多少个逆序对数。那么逆序对数为k的这样自然数数列到底有多少个?
输入输出格式
输入格式:
第一行为两个整数n,k。
输出格式:
写入一个整数,表示符合条件的数列个数,由于这个数可能很大,你只需输出该数对10000求余数后的结果。
输入输出样例
输入样例#1:
4 1
输出样例#1:
3
说明
样例说明:
下列3个数列逆序对数都为1;分别是1 2 4 3 ;1 3 2 4 ;2 1 3 4;
测试数据范围
30%的数据 n<=12
100%的数据 n<=1000,k<=1000
一道简单题,但我觉得可以做到更大的数据,比方说加两个0
从小到大考虑每一位,先考虑1,如果1位于i这个位置,那1与1~i-1这些位置的每一个数都会产生一个逆序对,与i+1~n这些位置的数都不会产生逆序对,至于具体每个数字是什么对于1的贡献没有影响
然后从排列里把1去掉,变成一个2~n的排列,这个排列与1~n-1的排列是等价的,于是问题转化成了一个较小的问题
然后可以dp
dp[i][j]表示1~i的排列,要有j个逆序对的方法数,枚举当前位置产生的逆序对来转移,这个东西本来是nk^2的,但是发现一个位置转移的时候是连续的一段,用前缀和优化去掉一个k即可
其实这个问题等价于有n个带编号的盒子排成一列,一共放k个球,标号为i的盒子里不能放超过i-1个球,求方法总数,这应该是有更好的做法的
UPD1:这个东西的生成函数是 $ (1)(1+x)(1+x+x^2)(1+x+x^2+x^3)...(1+x+x^2+...+x^{n-1}) $ 即 $ prod_{p=1}^{n}sum_{q=0}^{p-1}x^q $ ,这个形式过于美妙让人很难不认为它有一个优美的通解
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstdio> 4 #include <algorithm> 5 #include <string> 6 #include <cstring> 7 #include <cmath> 8 #include <map> 9 #include <stack> 10 #include <set> 11 #include <vector> 12 #include <queue> 13 #include <time.h> 14 #define eps 1e-7 15 #define INF 0x3f3f3f3f 16 #define MOD 10000 17 #define rep0(j,n) for(int j=0;j<n;++j) 18 #define rep1(j,n) for(int j=1;j<=n;++j) 19 #define pb push_back 20 #define mp make_pair 21 #define set0(n) memset(n,0,sizeof(n)) 22 #define ll long long 23 #define ull unsigned long long 24 #define iter(i,v) for(edge *i=head[v];i;i=i->nxt) 25 #define max(a,b) (a>b?a:b) 26 #define min(a,b) (a<b?a:b) 27 #define print_runtime printf("Running time:%.3lfs ",double(clock())/1000.0) 28 #define TO(j) printf(#j": %d ",j); 29 //#define OJ 30 using namespace std; 31 const int MAXINT = 100010; 32 const int MAXNODE = 100010; 33 const int MAXEDGE = 2*MAXNODE; 34 char BUF,*buf; 35 int read(){ 36 char c=getchar();int f=1,x=0; 37 while(!isdigit(c)){if(c=='-') f=-1;c=getchar();} 38 while(isdigit(c)){x=x*10+c-'0';c=getchar();} 39 return f*x; 40 } 41 char get_ch(){ 42 char c=getchar(); 43 while(!isalpha(c)) c=getchar(); 44 return c; 45 } 46 //------------------- Head Files ----------------------// 47 48 int n,k; 49 int dp[10010],sum[10010]; 50 void get_input(); 51 void work(); 52 int main() { 53 get_input(); 54 work(); 55 return 0; 56 } 57 void work(){ 58 fill(sum,sum+k+1,1); 59 for(int i=2;i<=n;i++){ //box no i,can take 0~i-1 60 rep0(j,k+1){ 61 dp[j] = (j-i+1>0?sum[j]-sum[j-i]:sum[j]); 62 } 63 sum[0]=dp[0]; 64 rep1(j,k){ 65 sum[j]=(sum[j-1]+dp[j])%MOD; 66 } 67 } 68 printf("%d ",(dp[k]+MOD)%MOD); 69 } 70 void get_input(){ 71 n=read();k=read(); 72 }