考场上的我猜测到了某个题是二项式反演 可惜我不会啊

分治NTT给了60的暴力 然而他们的分治NTT都能跑1e6/dk

回归正题

二项式反演大概就是关于二项式的反演(废话)

一般来说 初始状态都是状压的0/1状态 然后它们有很好的性质 与具体哪一位的状态无关 所以可以直接记录1的个数

又因为反演≈容斥 所以它的两个基本形式就很好看了

$f(n) = \sum_{i=0} ^ n  (-1)^i \binom{n}{i} g(i) \Leftrightarrow g(n) = \sum_{i=0} ^n (-1)^i \binom{n}{i} f(i)$

一般这个柿子用不到(吧 因为很少上来就是个容斥形式

$f(n) = \sum _{i=0} ^n \binom{n}{i} g(i) \Leftrightarrow g(n)=\sum_{i=0}^n (-1)^{n-i} \binom{n}{i} f(i)$

一般是这个柿子比较有用qwq

具体证明自行百度吧(~~其实就是我懒~~

 

例题

[HAOI2016] 染色

其实这个题完全可以不用二项式反演直接容斥 也间接性证明了反演的本质就是容斥

考虑恰好为S有k个的限制 按照套路转化为至少有k个为S

设所求函数为G(x) 容斥函数为F(x)

容斥函数可直接计算$F(x) = \binom{m}{x} (m-i)^{n-ix} \frac{(sx)!}{(x!)^s (n-ix)!}$

然后直接套上上边的容斥就可以了

最后NTT优化即可

以前的代码(反正最后柿子推出来是一样的)

//Love and Freedom.
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define ll long long
#define inf 20021225
#define mdn 1004535809
#define N 300010
#define G 3
using namespace std;

int rev[N<<2],inv,jc[N*100],iv[N*100],n,m,s,w[N];
int ksm(int bs,int mi)
{
    int ans=1;
    while(mi)
    {
        if(mi&1)    ans=(ll)ans*bs%mdn;
        bs=(ll)bs*bs%mdn; mi>>=1;
    }
    return ans;
}
int pre(int n)
{
    int lim=1,l=0;
    while(lim<n)    lim<<=1,l++;
    for(int i=1;i<lim;i++)
        rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
    inv=ksm(lim,mdn-2); return lim;
}
void ntt(int *a,int lim,int opt)
{
    for(int i=1;i<lim;i++)    if(i<rev[i])
        swap(a[i],a[rev[i]]);
    for(int k=2,mid=1;k<=lim;k<<=1,mid<<=1)
    {
        int Wn=ksm(G,(mdn-1)/k);    if(opt)    Wn=ksm(Wn,mdn-2);
        for(int w=1,i=0;i<lim;w=1,i+=k)    for(int j=0;j<mid;j++,w=(ll)w*Wn%mdn)
        {
            int x=a[i+j],y=(ll)w*a[i+mid+j]%mdn;
            a[i+j]=(x+y)%mdn; a[i+mid+j]=(x-y+mdn)%mdn;
        }
    }
    if(opt)    for(int i=0;i<lim;i++)    a[i]=(ll)a[i]*inv%mdn;
}
int h[N],f[N],ans[N]; int top;
int main()
{
    scanf("%d%d%d",&n,&m,&s);
    for(int i=0;i<=m;i++)    scanf("%d",&w[i]);
    top=min(n/s,m); jc[0]=iv[0]=1; int tt=max(n,m);
    for(int i=1;i<=tt;i++)    jc[i]=(ll)jc[i-1]*i%mdn;
    iv[tt]=ksm(jc[tt],mdn-2); int qwq=1;
    for(int i=tt;i;i--)    iv[i-1]=(ll)iv[i]*i%mdn;
    for(int i=0;i<=top;i++)
        f[i]=(ll)jc[m]*iv[m-i]%mdn*jc[n]%mdn*iv[n-i*s]%mdn*qwq%mdn*ksm(m-i,n-i*s)%mdn,qwq=(ll)qwq*iv[s]%mdn;
    for(int i=0;i<=top;i++)    h[i]=(ll)(mdn+((i&1)?-1:1)*iv[i])%mdn;
    for(int i=0;i<=(top>>1);i++)    swap(h[i],h[top-i]);
    int lim=pre((top+1)<<1);// printf("%d\n",lim);
    ntt(h,lim,0); ntt(f,lim,0);
    for(int i=0;i<lim;i++)    ans[i]=(ll)h[i]*f[i]%mdn;
    ntt(ans,lim,1); int fin=0;
    for(int i=0;i<=top;i++)
        fin=(ll)(fin+(ll)ans[top+i]*w[i]%mdn*iv[i]%mdn)%mdn;
    printf("%d\n",fin);
    return 0;
}
View Code

相关文章:

猜你喜欢
  • 2021-12-16
  • 2021-07-19
  • 2021-06-11
相关资源
相似解决方案