BZOJ3027:Sweet/BZOJ1272:Gate Of Babylon(生成函数+广义二项式定理+卢卡斯定理)

生成函数 专栏收录该内容
12 篇文章 0 订阅

题面
首先问题可以差分

对于每一罐都搞一个生成函数
大概是 1xm+11x 1 − x m + 1 1 − x
总方案数的生成函数就是

1(1x)ni=1n(1mi) 1 ( 1 − x ) n ∏ i = 1 n ( 1 − m i )

=(1x)ni=1n(1mi) = ( 1 − x ) − n ∏ i = 1 n ( 1 − m i )

传说中的性质

i=0ooCin+i1xi=(1x)n ∑ i = 0 o o C n + i − 1 i x i = ( 1 − x ) − n

展开
由于n比较小,我们可以枚举 ni=1(1mi) ∏ i = 1 n ( 1 − m i ) 的每项系数f
f[k] f [ k ] 的贡献,大概为
i=0bkCn1ni1=Ckn+mk ∑ i = 0 b − k C n − i − 1 n − 1 = C n + m − k k

两题几乎一样
BZOJ1272要用卢卡斯定理

bzoj3027

#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;
#define mmst(a, b) memset(a, b, sizeof(a))
#define mmcp(a, b) memcpy(a, b, sizeof(b))

typedef long long LL;

const int N=2020;
const LL p=2004;

LL mo=2004,jc=1;
LL n,nn,a,b,m[N];

LL C(LL x,LL y)
{
    if(x<y)
    return 0;
    LL res=1;
    for(int i=x;i>=x-y+1;i--)
    res=res*i%mo;
    return (res/jc)%p;
}

LL work(LL x)
{
    LL res=0;
    for(int i=0;i<=nn;i++)
    {
        LL s=x,ops=1;
        for(int j=1;j<=n;j++)
        if((1<<(j-1))&i)
        ops=-ops,s-=m[j]+1;
        if(s<0)
        continue;
        res+=C(s+n,n)*ops;
    }
    return res%p;
}

int main()
{
    cin>>n>>a>>b;;
    nn=(1<<n)-1;

    for(int i=2;i<=n;i++)
    jc*=i,mo*=i;

    for(int i=1;i<=n;i++)
    cin>>m[i];
    cout<<((work(b)-work(a-1))%p+p)%p<<endl;

    return 0;
}

bzoj1272

#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;
#define mmst(a, b) memset(a, b, sizeof(a))
#define mmcp(a, b) memcpy(a, b, sizeof(b))

typedef long long LL;

const int N=1234567;

LL n,T,p,m,nn,ans;
LL b[N];
LL jc[N],Ijc[N],I[N];

LL C(LL x,LL y)
{
    if(x<y)
    return 0;
    if(x<p)
    return jc[x]*Ijc[y]%p*Ijc[x-y]%p;
    return C(x/p,y/p)*C(x%p,y%p)%p; 
}

int main()
{
    cin>>n>>T>>m>>p;
    nn=(1<<T)-1;

    for(int j=1;j<=T;j++)
    scanf("%d",&b[j]);

    I[1]=Ijc[0]=jc[0]=1;
    for(int i=2;i<p;i++)
    I[i]=I[p%i]*(p-p/i)%p;

    for(int i=1;i<p;i++)
    jc[i]=jc[i-1]*i%p,Ijc[i]=Ijc[i-1]*I[i]%p;

    for(int i=0;i<=nn;i++)
    {
        LL ops=1,s=m;
        for(int j=1;j<=T;j++)
        if(i&(1<<(j-1)))
        ops=-ops,s-=b[j]+1;
        if(s<0)
        continue;
        ans=(ans+ops*C(n+s,n)+p)%p;
    }

    cout<<ans<<endl;

    return 0;
}
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值