zoukankan      html  css  js  c++  java
  • loj6077. 「2017 山东一轮集训 Day7」逆序对

    题目描述:

    loj

    题解:

    容斥+生成函数。

    考虑加入的第$i$个元素对结果的贡献是$[0,i-1]$,我们可以列出生成函数。

    长这样:$(1)*(1+x)*(1+x+x^2)*……*(1+x+x^2+……+x^{n-1})=frac{prod_{i=1}^{n}1-x^i}{(1-x)^n}$

    把分母提出来:$frac{1}{(1-x)^n} = (1+x+x^2+……)^n = sum_{i=0}^{k} C_{i+n-1}^{n-1}$,日常小球放盒。

    现在还剩$prod_{i=1}^n 1-x^i$,可以考虑将该式理解为从$1$到$n$选$i$个数,总和为$j$,对该项系数贡献为$(-1)^i$。

    由于从$1$到$n$不重复,可以发现$sum_{i=1}^{447}>100000$,那么$i le 447$。

    那么就可以$dp$了。状态为$f[i][j]$,表示当前选了$i$个数总和为$j$,且最后一项不大于$n$的方案数。

    要求选数不重复怎么办?

    考虑将其构造成一个上升序列。我们用枚举差值的思想,保证前后差值大于$0$。

    转移有三种:

    1.将$i$个数集体+1,此时$f[i][j]+=f[i][j-i]$;

    2.将$i$个数集体+1再在最前面加入一个1,此时$f[i][j]+=f[i-1][j-i]$;

    3.考虑我们每次都让每个数+1,所以当$j>n$时会出现最后一项为$n+1$的情况,此时$f[i][j]-=f[i-1][j-n-1]$;

    这样转移就可以了。

    最后卷积卷出第$k$位的值就可以了。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int MOD = 1000000007;
    const int N = 100050;
    const int M = 450;
    int fastpow(int x,int y)
    {
        int ret = 1;
        while(y)
        {
            if(y&1)ret=1ll*ret*x%MOD;
            x=1ll*x*x%MOD;y>>=1;
        }
        return ret;
    }
    template<typename T>
    inline void Mod(T&x){if(x>=MOD)x-=MOD;}
    int n,m;
    int jc[N<<1],jny[N<<1],f[M][N];
    void init()
    {
        jc[0] = 1;
        for(int i=1;i<=n+m;i++)jc[i]=1ll*jc[i-1]*i%MOD;
        jny[n+m] = fastpow(jc[n+m],MOD-2);
        for(int i=n+m;i;i--)jny[i-1]=1ll*jny[i]*i%MOD;
    }
    int C(int x,int y){return 1ll*jc[x]*jny[y]%MOD*jny[x-y]%MOD;}
    
    int main()
    {
        scanf("%d%d",&n,&m);
        init();
        f[0][0] = 1;
        for(int i=1;i<M;i++)for(int j=i;j<=m;j++)
        {
            Mod(f[i][j] = f[i-1][j-i]+f[i][j-i]);
            if(j>n)Mod(f[i][j]+=MOD-f[i-1][j-n-1]);
        }
        int ans = 0;
        for(int i=0;i<=m;i++)
        {
            int tmp = 0;
            for(int j=0;j<M;j++)
                if(j&1)Mod(tmp+=MOD-f[j][i]);
                else Mod(tmp+=f[j][i]);
            Mod(ans+=1ll*tmp*C(n+m-i-1,n-1)%MOD);
        }
        printf("%d
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    ubuntu安装Sogou输入法失败
    二进制转换与此平台上的长模式不兼容
    thinkpad e570 如何进入bios
    计算beta分布并画图(1)
    python利用pandas和xlrd读取excel,特征筛选列
    python利用jieba进行中文分词去停用词
    python利用heapq实现小顶堆(查找最大的N个元素)
    python根据索引删除内容并写入文本
    [Water]UVA 11792 Commando War
    [最大子序列和]Hdu 5280 Senior's Array
  • 原文地址:https://www.cnblogs.com/LiGuanlin1124/p/11136070.html
Copyright © 2011-2022 走看看