zoukankan      html  css  js  c++  java
  • [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 }


     

  • 相关阅读:
    vue-webpack介绍
    vue-ES6模块化的导入和导出
    vue-前端模块化
    vue-插槽作用域的使用
    vue-具名插槽的使用
    vue-插槽的基本使用
    vue-父组件获取子组件对象实例
    IO(六)
    IO(五)
    关于overflow:hidden
  • 原文地址:https://www.cnblogs.com/yyf0309/p/5674637.html
Copyright © 2011-2022 走看看