• 51nod 1020 逆序排列——dp


    在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。
    如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
    我们记f【i】【j】i 的全排列中逆序数为j的数量
    f【i】【j】=f【i-1】【k】 max(0,j-i+1)<=k<=j
    因为你插入 i 这个数进入 i-1 的全排列中 你插入位置后面的数的逆序对全部+1
    然后就解决问题辣
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int mod=1e9+7;
    int read(){
        int ans=0,f=1,c=getchar();
        while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
        return ans*f;
    }
    int f[1007][20007],s[20007];
    void prepare(){
        f[1][0]=1;
        for(int i=2;i<=1000;i++){
            s[0]=f[i-1][0];
            for(int j=1;j<=20000;j++) s[j]=(s[j-1]+f[i-1][j])%mod;
            for(int j=0;j<=20000;j++){
                int l=max(0,j-i+1),r=j;
                if(l-1>=0) f[i][j]=(s[r]-s[l-1])%mod;
                else f[i][j]=s[r];
            }
        }
    }
    int T,n,k;
    int main(){
        prepare();
        T=read(); while(T--) n=read(),k=read(),printf("%d
    ",(f[n][k]+mod)%mod);
        return 0;
    }
    View Code
    
    
    
     
  • 相关阅读:
    [JZOJ3388] 绿豆蛙的归宿

    [JZOJ3464] 秀姿势
    [JZOJ3462] 休息
    [JZOJ3461] 小麦亩产一千八
    [JZOJ3509] 倒霉的小C
    [JZOJ1267] 路障
    CF52C Circular RMQ
    P4162 [SCOI2009]最长距离
    P4047 [JSOI2010]部落划分
  • 原文地址:https://www.cnblogs.com/lyzuikeai/p/7441347.html
Copyright © 2020-2023  润新知