• CF451E Devu and Flowers


    思路

    母函数

    题目等价于求这样的一个问题

    给出n个变量(x_1,x_2,dots,x_n),求方程(x_1+x_2+x_3+dots+x_n=S)的整数解方案数且要满足(x_1le f_1.x_2le f_2,dots,x_nle f_n)

    乍一看不是很好做,那怎么办?

    看到(nle20),状压?其实生成函数也可以做

    写出整个的生成函数

    [G(x)=(1+x+x^2+dots+x^{f_1})(1+x+x^2+dots+x^{f_2})dots(1+x+x^2+dots+x^{f_n}) ]

    通过等比数列求和公式,可以化成这样

    [G(x)=frac{(1-x^{f_1+1})(1-x^{f_2+1})dots (1-x^{f_n+1})}{(1-x)^n} ]

    答案就是第s项系数

    然后通过生成函数的公式

    [G(x)= (1-x^{f_1+1})(1-x^{f_2+1})dots (1-x^{f_n+1})sum_{i=0}^{infty}left(egin{matrix}n+i-1\n-1end{matrix} ight)x^i ]

    前面的暴力展开,最多有(2^n)项且系数只会有1或-1

    考虑后面的项怎么做

    假设现在求出了第k项,我们需要在后面的式子的第s-k项系数(如果k>s,忽略即可)

    第s-k项的系数就是(left(egin{matrix}n+s-k-1\n-1end{matrix} ight)​),但是s有(10^{14}​),我们还需要变形一下

    [egin{align}&left(egin{matrix}n+s-k-1\n-1end{matrix} ight)\=&frac{(n+s-k-1)!}{(n-1)!(s-k)!}\=&frac{prod_{i=s-k+1}^{n+s-k-1}i}{(n-1)!}end{align} ]

    然后就相当可做了

    容斥

    看到20,想到状压
    2^n枚举那几个x超过限制,则它们至少都有(f_x+1)个,从s中减去这些,剩下的随意分配,就相当于求方程(x_1+x_2+dots+x_n=s)的整数解个数,利用组合数学的知识,用0的个数表示每个x的大小,相当于加入n-1个1分割0的方案数,或者是多重集合({0·s,1*(k-1)})的排列数,就是(left(egin{matrix}s-m+n-1\n-1end{matrix} ight))
    这样显然相当于是至少x个不超过限制,其他没有限制,所以枚举子集容斥即可

    其实最后的式子两个一模一样

    代码

    母函数版

    #include <set>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #define int long long
    const int MOD = 1000000007;
    using namespace std;
    int jcn_1=1,inv_jcn_1,n,f[100],s,ans=0;
    int pow(int a,int b){
        int ans=1;
        a%=MOD;
        while(b){
            if(b&1)
                ans=(ans*a)%MOD;
            a=(a*a)%MOD;
            b>>=1;
        }
        return ans;
    }
    int C(int k){//k
        int ans=1;
        for(int i=s-k+1;i<=n+s-k-1;i++)
            ans=(ans*(i%MOD))%MOD;
        return ans*inv_jcn_1%MOD;
    }//return c(x,n-1)
    void dfs(int pos,int opt,int x){
        if(pos==n){
            if(x>s)
                return;
            ans=((ans+opt*C(x))%MOD+MOD)%MOD;
            return;
        }
        dfs(pos+1,opt,x);
        dfs(pos+1,-opt,x+f[pos+1]+1);
    }
    signed main(){
        scanf("%I64d %I64d",&n,&s);
        for(int i=1;i<n;i++)
            jcn_1*=i;
        inv_jcn_1=pow(jcn_1,MOD-2);
        for(int i=1;i<=n;i++)
            scanf("%I64d",&f[i]);
        dfs(0,1,0);
        printf("%I64d
    ",ans);
        return 0;
    }
    

    容斥版

    咕咕咕

  • 相关阅读:
    数据结构 【实验 串的基本操作】
    Ioc容器依赖注入-Spring 源码系列(2)
    定时任务管理中心(dubbo+spring)-我们到底能走多远系列47
    jvm内存增长问题排查简例
    Ioc容器beanDefinition-Spring 源码系列(1)
    SPI机制
    java工厂-积木系列
    java单例-积木系列
    利用spring AOP 和注解实现方法中查cache-我们到底能走多远系列(46)
    java 静态代理-积木系列
  • 原文地址:https://www.cnblogs.com/dreagonm/p/10518114.html
Copyright © 2020-2023  润新知