zoukankan      html  css  js  c++  java
  • BZOJ2431 [HAOI2009]逆序对数列

    Description

    对于一个数列{ai},如果有i<j且ai>aj,那么我们称ai与aj为一对逆序对数。若对于任意一个由1~n自然数组成的数列,可以很容易求出有多少个逆序对数。那么逆序对数为k的这样自然数数列到底有多少个?

    Input

     第一行为两个整数n,k。

    Output

    写入一个整数,表示符合条件的数列个数,由于这个数可能很大,你只需输出该数对10000求余数后的结果。

     


    Sample Input

    样例输入

    4 1


    Sample Output

    样例输出

    3

    样例说明:

    下列3个数列逆序对数都为1;分别是1 2 4 3 ;1 3 2 4 ;2 1 3 4;



    测试数据范围

    30%的数据 n<=12

    100%的数据 n<=1000,k<=1000

     

     
     
    正解:DP(递推)
    解题报告:
      这道题我居然没能一眼秒。。。
      令f[i][j]表示前i个数逆序对数为j的序列个数,考虑DP(递推)。因为插入前i-1个数的时候方案已经得出了,我们需要插入第i个数获得新的一些序列。
      因为i比前面任何一个数都要大,所以插在第几位,就会比后面的数大,对于总逆序对产生贡献。考虑贡献大小,可以插在前i-1个数的最后面,那么对于逆序对数没有产生任何贡献,所以就是从f[i-1][j]转移过来,但是插在其他位置呢?如果插在i-2个数后面就是产生1的贡献,所以是f[i-1][j-1]。。。最后i-1中总共i-1个数,所以新产生的贡献最大为i-1。可以得到方程式:f[i][j]=∑f[i-1][j-k](0<=k<i)
      复杂度O(N^3)但是可以优化。因为每次用的是一段,所以前缀和优化一下,没必要每次重新统计。
     
     1 //It is made by jump~
     2 #include <iostream>
     3 #include <cstdlib>
     4 #include <cstring>
     5 #include <cstdio>
     6 #include <cmath>
     7 #include <algorithm>
     8 #include <ctime>
     9 #include <vector>
    10 #include <queue>
    11 #include <map>
    12 #include <set>
    13 #ifdef WIN32   
    14 #define OT "%I64d"
    15 #else
    16 #define OT "%lld"
    17 #endif
    18 using namespace std;
    19 typedef long long LL;
    20 const int MAXN = 1011;
    21 const int MOD = 10000;
    22 int n,k;
    23 int f[MAXN][MAXN];//f[i][j]表示前i个数逆序对为j个的序列数
    24 
    25 inline int getint()
    26 {
    27        int w=0,q=0;
    28        char c=getchar();
    29        while((c<'0' || c>'9') && c!='-') c=getchar();
    30        if (c=='-')  q=1, c=getchar();
    31        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
    32        return q ? -w : w;
    33 }
    34 
    35 inline void work(){
    36     n=getint(); k=getint();
    37     f[0][0]=1; for(int i=1;i<=n;i++) f[i][0]=1;
    38     int now=0;
    39     for(int i=1;i<=n;i++) {//新加入的i可以插在之前的i-1个数中的任意位置,就会产生对逆序对数不同的贡献,可能贡献为0但最多为i-1。所以能加入当前的范围为j-i+1到j
    40     now=f[i-1][0];
    41     for(int j=1;j<=k;j++){
    42         if(j-i>=0)  now-=f[i-1][j-i];
    43         now+=f[i-1][j];
    44         f[i][j]+=now;
    45         f[i][j]+=MOD; if(f[i][j]>=MOD) f[i][j]%=MOD;
    46     }
    47     }
    48     printf("%d",f[n][k]);
    49 }
    50 
    51 int main()
    52 {
    53   work();
    54   return 0;
    55 }
     
  • 相关阅读:
    Mysql关键字冲突的解决方案
    js日期时间函数
    Mysql字符串字段中是否包含某个字符串,用 find_in_set
    mysql中 where in 用法
    Best of Best系列(4)——AAAI
    Best of Best系列(5)——IJCAI
    Best of Best系列(3)——ICML
    Best of Best系列(6)——SIGIR
    Best of Best系列(2)——ICCV
    Best of Best系列(1)——CVPR
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/5803808.html
Copyright © 2011-2022 走看看