生成函数例题

题解

构造生成函数
image
那么相乘得到\(F(x)=\frac{x}{1-x^4}=x\sum_{i\geq 0}{i+4-1\choose i}x^i=\sum_{i\geq 1}{i+3\choose i}x^i\)
\(ans=[x^n]F(x)=\frac{n(n+1)(n+2)}{6}\)

题解

构造生成函数\(F_i(x)=1+x+x^2+···+x^{f_i}=\frac{1-x^{f_i+1}}{1-x}\)
\(F(x)=F_1(x)F_2(x)···F_n(x)=\frac{\prod_{i=1}^n(1-x^{f_i+1} )} {(1-x)^n}\)
因为\(n\geq 20\)很小,那么可以在\(O(2^n)内求出A(x)=\prod_{i=1}^n(1-x^{f_i+1} )\)
\(ans=[x^s]F(x)=\sum_{i=0}^s[x^i]A(x)\cdot [x^{s-i}]\frac{1}{(1-x)^n}=\sum_{i=0}^s[x^i]A(x)\cdot [x^{s-i}]{s-i+n-1 \choose n-1}\)

点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#define ll long long 
using namespace std;
const int maxn=2e6+101;
const ll MOD=1e9+7;
const int inf=2147483647;
ll read(){
    ll x=0,f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
    return x*f;
}
ll n,s,f[21],inv[30];
int cnt;
struct wzq{ll x,y;}a[maxn];
void dfs(ll x,ll y,ll z){
    if(y>s)return ;
    if(x==n+1){a[++cnt].x=y;a[cnt].y=z;return ;}
    dfs(x+1,y,z);
    dfs(x+1,y+f[x],-1*z);
    return ;
}
bool cmp(wzq i,wzq j){return i.x<j.x;}
ll get(ll x,ll y){
    ll ans=1ll;
    for(ll i=0;i<x;i++){
        ans=(ans%MOD)*((y-i)%MOD)%MOD;
        ans=ans*inv[i+1]%MOD;
    }
    return ans%MOD;
}
int main(){
    n=read();s=read();for(int i=1;i<=n;i++)f[i]=read()+1;
    dfs(1,0,1);sort(a+1,a+cnt+1,cmp);
    int sum=1;
    for(int i=2;i<=cnt;i++){
        if(a[i].x==a[i-1].x)a[sum].y+=a[i].y;
        else {
            a[++sum].x=a[i].x;
            a[sum].y=a[i].y;
        }
    }
    inv[1]=1ll;for(ll i=2;i<30;i++)inv[i]=(ll)(((-MOD/i)*inv[MOD%i])%MOD+MOD)%MOD;
    ll ans=0;
    for(int i=1;i<=sum;i++)ans=(ans+(a[i].y*get((ll)(n-1),(ll)(s-a[i].x+n-1ll)))%MOD)%MOD;
    printf("%lld",(ans%MOD+MOD)%MOD);
    return 0;
}

题解

由上一题可得\(ans=\sum_{S=a}^b[x^S]F(x)=\sum_{S=a}^b\sum_{i=0}^S[x^i]A(x)\cdot [x^{s-i}]{s-i+n-1 \choose n-1}\)
显然这个式子的复杂度会超时,那么继续化简,交换求和号
\(ans=\sum_{i=0}^S[x^i]F(x)\sum_{S=a}^b{s-i+n-1 \choose n-1}\)
\(\sum_{S=a}^b{s-i+n-1 \choose n-1}={b-i+n \choose n}-{a-i+n-1 \choose n}\)
由杨辉三角可证
image

\(ans=\sum_{i=0}^S[x^i]F(x)({b-i+n \choose n}-{a-i+n-1 \choose n})\)
注意对于模数非质数的除法,可以先把模数乘上除数,再将运算结果除以除数得到答案。

点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#define ll long long 
using namespace std;
const int maxn=2001;
const ll MOD=2004;
const int inf=2147483647;
ll read(){
    ll x=0,f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
    return x*f;
}
ll n,la,lb,f[21];
int cnt;
struct wzq{ll x,y;}a[maxn];
void dfs(ll x,ll y,ll z){
    if(y>lb)return ;
    if(x==n+1){a[++cnt].x=y;a[cnt].y=z;return ;}
    dfs(x+1,y,z);
    dfs(x+1,y+f[x],-1*z);
    return ;
}
bool cmp(wzq i,wzq j){return i.x<j.x;}
ll get(ll x,ll y){
    if(x>y)return 0;
    ll ans=1ll,in=1;
    for(int i=1;i<=n;i++)in*=i;
    ll MODD=in*MOD;
    for(ll i=0;i<x;i++)ans=(ans%MODD)*((y-i)%MODD)%MODD;
    return (ans/in)%MOD;
}
int main(){
    n=read();la=read();lb=read();
    for(int i=1;i<=n;i++)f[i]=read()+1;
    dfs(1,0,1);sort(a+1,a+cnt+1,cmp);
    int sum=1;
    for(int i=2;i<=cnt;i++){
        if(a[i].x==a[i-1].x)a[sum].y+=a[i].y;
        else {
            a[++sum].x=a[i].x;
            a[sum].y=a[i].y;
        }
    }
    ll ans=0;
    for(int i=1;i<=sum;i++){
        ans=ans+(a[i].y*(get(n,(lb-a[i].x+n))-get(n,(la-a[i].x+n-1)))%MOD)%MOD;
        ans%=MOD;
    }
    printf("%lld",(ans%MOD+MOD)%MOD);
    return 0;
}
posted @ 2021-11-23 13:34  I_N_V  阅读(120)  评论(0编辑  收藏  举报