[noip模拟题]排队

【问题描述】

      小sin所在的班有n名同学,正准备排成一列纵队,但他们不想按身高从矮到高排,那样太单调,太没个性。他们希望恰好有k对同学是高的在前,矮的在后,其余都是矮的在前,高的在后。如当n=5,k=3时,假设5人从矮到高分别标为1、2、3、4、5,则(1,5,2,3,4)、(2,3,1,5,4)、(3,1,4,2,5)都是可行的排法。小sin想知道总共有多少种可行排法。

【输入】

      输入文件名为lineup.in。

      一行两个整数n和k,意义见问题描述。

【输出】

      输出文件名为lineup.out。

      输出一个整数,表示可行排法数。由于结果可能很大,请输出排法数mod 1799999的值。

 

【输入输出样例】

lineup.in

lineup.out

5 3

15

 

【数据范围】

      对于20%的数据,有n≤10,k≤40;

      对于60%的数据,有n≤100,k≤500;

      对于100%的数据,有n≤100,k≤n*(n-1)/2。


 

  这道题并不是特别地难,其实只需要这样分析,假设把第i个同学加入前面(i-1)个同学组成的有j‘组逆序对的队列中(假设加入的同学的大小从低到高)

,这时i同学插在最后面不会增加逆序对的个数,但是插在第k(从后往前数)位同学前面会增加k个逆序对(第i个同学身高最高),如下:

  原队列:  1  4  2  3

  将第5个同学插入第2(k = 3)位同学前: 1  5  4  2  3

  上面褐色就是和这个数产生的逆序对的个数。

那么达到一个状态(i,j)就是第(i- 1)个人组成的队列所有能够通过插入第i个同学得到的j个逆序对

  这么说也存在不可能的时候

  比如原队列:  1  2  3

  插入进去后要使逆序对的数量增加到4个,要使增加的逆序对的个数最大,即将第4位同学增加到队首,增加3个逆序对,0 + 3 < 4

所以这种情况是不可能的

  于是还要满足这个条件(假设之前这个逆序对的个数为k)  k + i - 1 > j

  得到了这个递推式(f的初值为0)(如果下表为负也不用管)

f[i][j] = f[i - 1][j] + f[i - 1][j - 1] +...+ f[i - 1][j - i + 1]

  貌似这样的时间复杂度是O(kn2)对于100这样的范围还是可以过的

  不过明明是可以再继续优化,就只用个前缀和就可以轻松代替第三重循环,也可以化简一下上面的递推式

,总之有很多方法可以消去第三重循环

Code

 1 #include<iostream>
 2 #include<fstream>
 3 #define moder 1799999
 4 using namespace std;
 5 ifstream fin("lineup.in");
 6 ofstream fout("lineup.out");
 7 int f[101][5051];
 8 long long s[101][5051];
 9 int n,k;
10 int buf;
11 void init_dp(){
12     for(int i = 2;i <= n;i++){
13         f[i][0] = 1;
14         s[i][0] = 1;
15     }
16 }
17 void dp(){
18     f[2][1] = 1;
19     s[2][1] = s[2][0] + 1;
20     for(int i = 3;i <= n;i++){
21         buf = (i - 1)*(i - 2)/2;
22         for(int j = 1;j < i ;j++){
23             f[i][j] = s[i - 1][min(j,buf)];
24             s[i][j] = (s[i][j - 1] + f[i][j]) % moder;
25         }
26         for(int j = i ;j <=i*(i - 1)/2;j++){
27             f[i][j] = (s[i - 1][min(buf,j)] - s[i - 1][j - i] + moder) % moder;
28             s[i][j] = (s[i][j - 1] + f[i][j]) % moder;
29         }
30     }
31 }
32 int main(){
33     fin>>n>>k;
34     init_dp();
35     dp();
36     fout<<f[n][k];
37     return 0;
38 }


 

posted @ 2016-07-15 19:37  阿波罗2003  阅读(246)  评论(0编辑  收藏  举报