ZOJ 2284 题解

    题目链接:http://acm.zju.edu.cn/show_problem.php?pid=2284

    序列题又出现了,题目比较有意思。
    意思大概是这样的,给出一个数字n,在1,2,3,4......n的这些数字中找出

组合的个数,要求这些组合的共同点是它的inversion number是k,一个

inversion number的意思就是1<=i<j<=n and Ai>Aj.例如:2,3,1的inversion

number是2,因为2和1,3和1是2个inversion number。
    一开始,我的做法是dfs,不过很显然,这样肯定超时,测试了一下,果然

超时。后来想想这个题目貌似可以用dp,还是很简单的dp。可以这样看,m[i]

[j]表示n=i,k=j时候的结果,要求m[i][j],只要知道了m[i-1][...]就可以了,

比如已知m[3][0],m[3][1],m[3][2],m[3][3],m[3][4]......,现在要求m[4]

[k],要做的只有把4插入到前面三个中有可能插的地方,例如1,2,3可以插的地方

是1前面,1,2之间,2,3之间,3后面,因为4是这些数中最大的数,这样每次插入

产生的新的inversion number的数量是可以直接知道的,只要利用这样简单的关

系,就可以得到m[1][0]到m[20][200]所有的情况。
于是代码如下,in C++,时间是0秒,注意,这里貌似要用long long ,不然会wa

的。


代码
 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std ;
 4 long long m[21][201] ;
 5 
 6 void init()
 7 {
 8 for(int i = 0 ; i <=200 ; i ++)
 9    m[1][i] = 0 ;
10 m[1][0= 1 ;
11 for(int i = 2 ; i <= 20 ; i ++)
12    for(int j = 0 ; j <= 200 ; j ++)
13    {
14     m[i][j] = 0;
15     for(int k = 0 ; k < i && j - k >= 0 ; k ++)
16      m[i][j] += m[i - 1][j - k] ;
17 
18    }
19 }
20 int main()
21 {
22 int n , k ;
23 
24 init() ;
25 while(1)
26 {
27    scanf("%d%d",&n,&k) ;
28    if(n == 0 && k == 0)
29     break ;
30    printf("%lld\n",m[n][k]) ;
31 }
32 return 0 ;
33 }


posted on 2010-02-05 01:55  vivy  阅读(247)  评论(0编辑  收藏  举报