洛谷 P2513 [HAOI2009]逆序对数列

题目描述

对于一个数列{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\n",double(clock())/1000.0)
28 #define TO(j) printf(#j": %d\n",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\n",(dp[k]+MOD)%MOD);
69 }
70 void get_input(){
71        n=read();k=read();
72 }

 

posted @ 2017-05-30 19:01  LoveYayoi  阅读(191)  评论(0编辑  收藏  举报