zoukankan      html  css  js  c++  java
  • 51Nod 1020 逆序排列

                                                                                                1020 逆序排列

    在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。
    如2 4 3 1中,2 1,4 3,4 1,3 1是逆序,逆序数是4。
     
    1-n的全排列中,逆序数最小为0(正序),最大为n*(n-1) / 2(倒序)
    给出2个数n和k,求1-n的全排列中,逆序数为k的排列有多少种?
    例如:n = 4 k = 3。
     
    1 2 3 4的排列中逆序为3的共有6个,分别是:
    1 4 3 2
    2 3 4 1
    2 4 1 3
    3 1 4 2
    3 2 1 4
    4 1 2 3
     
    由于逆序排列的数量非常大,因此只需计算并输出该数 Mod 10^9 + 7的结果就可以了。
     
    Input
    第1行:一个数T,表示后面用作输入测试的数的数量。(1 <= T <= 10000)
    第2 - T + 1行:每行2个数n,k。中间用空格分隔。(2 <= n <= 1000, 0 <= k <= 20000)
    Output
    共T行,对应逆序排列的数量 Mod (10^9 + 7)
    Input示例
    1
    4 3
    Output示例
    6

    dp+离线处理
    我们很容易想到状态
    dp[i][j] 代表在i个数的全排列中有j 的逆序数的方案数
    下面我们来考虑这个状态的转移
    显然将 i 插入 i-1 的排列中 不同的位置会产生不同的方案数
    可能不产生逆序数 可能产生 1个 或 2个 或3个.....但最多能产生 i-1 个逆序数

    于是 f[i][j]=f[i-1][j]+f[i-1][j-1]+f[i-1][j-2]+f[i-1][j-3]+f[i-1][j-4].........+f[i-1][j-(i-1)];
    只有一个方程我们看不出怎么转移
    我们 再找另一个方程 f[i][j-1];
    f[i][j-1]=f[i-1][j-1]+f[i-1][j-1-1]+f[i-1][j-1-2]+f[i-1][j-1-2]...............f[i-1][j-1-(i-1)];

    显然两个方程右边是有许多相同项的
    我们用上式减去下式
    得到 f[i][j]-f[i][j-1]=f[i-1][j]-f[i-1][j-1-(i-1)];
    化简得到 f[i][j]=f[i][j-1]+f[i-1][j]-f[i-1][j-i];

    于是就可以转移了

     1 #include <cstdio>
     2 #include <cctype>
     3 
     4 const int mod=1000000007;
     5 const int MAXN=20010;
     6 
     7 int T,n,m;
     8 
     9 int dp[1010][MAXN];
    10 
    11 inline void read(int&x) {
    12     int f=1;register char c=getchar();
    13     for(x=0;!isdigit(c);c=='-'&&(f=-1),c=getchar());
    14     for(;isdigit(c);x=x*10+c-48,c=getchar());
    15     x=x*f;
    16 }
    17 
    18 int hh() {
    19     read(T);
    20     for(int i=1;i<=1000;++i) dp[i][0]=1;
    21     for(int i=2;i<=1000;++i)
    22       for(int j=1;j<=20000&&j<=i*(i-1)/2;++j) {
    23           dp[i][j]=(dp[i][j-1]+dp[i-1][j])%mod;
    24           if(j-i>=0) dp[i][j]=((dp[i][j]-dp[i-1][j-i])%mod+mod)%mod;
    25       } 
    26     while(T--) {
    27         read(n);read(m); 
    28         printf("%d
    ",dp[n][m]);
    29     }
    30     return 0;
    31 }
    32 
    33 int sb=hh();
    34 int main(int argc,char**argv) {;}
    代码



    作者:乌鸦坐飞机
    出处:http://www.cnblogs.com/whistle13326/
    新的风暴已经出现 怎么能够停止不前 穿越时空 竭尽全力 我会来到你身边 微笑面对危险 梦想成真不会遥远 鼓起勇气 坚定向前 奇迹一定会出现

     
  • 相关阅读:
    抽奖概率算法
    thinkphp 6.0 结合 layuiadmin (iframe版)
    d2-admin 学习记录
    判断点是否在多边形区域内外
    PHP 优秀资源汇集
    前端学习路线
    限制sa 登录IP
    vs2013发布.net程序
    游标批 量删除数据表
    sql server2012 还原数据库
  • 原文地址:https://www.cnblogs.com/whistle13326/p/7512237.html
Copyright © 2011-2022 走看看