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 }


     

  • 相关阅读:
    [ZJOI2007]时态同步 题解
    Xposed 在android 6.0上报couldn't load class,找不到xposed_init中配置的入口类
    微信小程序http 400问题
    在Mac上 python中使用tesseract OCR (Pytesser) 识别图片中的文字
    微信小游戏跳一跳简单手动外挂(基于adb 和 python)
    第一个微信小程序踩的几个小坑
    android studio/Intellij IDEA(MAC OSX)中android模拟器无法启动的一种原因
    【转载】word2vec原理推导与代码分析
    HTTP Get Post究竟有哪些区别
    初试kotlin:用Kotlin开发桌面/CommandLine 工具
  • 原文地址:https://www.cnblogs.com/yyf0309/p/5674637.html
Copyright © 2011-2022 走看看