• BZOJ 4555: [Tjoi2016&Heoi2016]求和 [FFT 组合计数 容斥原理]


    4555: [Tjoi2016&Heoi2016]求和

    题意:求$$
    sum_{i=0}^n sum_{j=0}^i S(i,j)cdot 2^jcdot j!
    S是第二类斯特林数

    [ *** 首先你要把这个组合计数肝出来,~~于是我去翻了一波《组合数学》~~ *分治fft做法见上一篇,本篇是容斥原理+fft做法* </br> ###组合计数 **斯特林数** $S(n,i)$表示将n个不同元素划分成i个相同集合非空的方案数 </br> 考虑**集合不相同**情况$S'(n,i)=S(n,i)*i!$,我们用**容斥原理**推♂倒她 ]

    每个集合非空的限制太强了,我们弱化它,可以有ge k个空集合
    ans = ge 0个空集合 - ge 1个空集合 + ge 2 个空集合
    S'(n,i) = sum_{k=0}^{i} (-1)^k inom{i}{k} (i-k)^n

    [最后的$(i-k)^n$含义是n个元素每个可以放入任意一个集合中 </br> 然后把这个式子带进去化啊化,具体过程[WerKeyTom_FTD大爷已经写过了](http://blog.csdn.net/WerKeyTom_FTD/article/details/51909966) **注意有一步把第一个带着i的求和移到最后,是一个等比数列求和** 最后得到的是 ]

    ans=sum_{j=0}^nj!2^jsum_{k=0}^jfrac{(-1)^k}{k!}*frac{sum_{i=0}^n(j-k)^i}{(j-k)!}

    [后面是卷积的形式,一遍ntt就行了 ```cpp #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; typedef long long ll; const int N=(1<<18)+5, INF=1e9; const ll P=998244353, g=3; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } ll Pow(ll a, ll b) { ll ans=1; for(; b; b>>=1, a=a*a%P) if(b&1) ans=ans*a%P; return ans; } namespace ntt{ int n, rev[N]; void ini(int lim) { n=1; int k=0; while(n<lim) n<<=1, k++; for(int i=0; i<n; i++) rev[i] = (rev[i>>1]>>1) | ((i&1)<<(k-1)); } void dft(ll *a, int flag) { for(int i=0; i<n; i++) if(i<rev[i]) swap(a[i], a[rev[i]]); for(int l=2; l<=n; l<<=1) { int m=l>>1; ll wn = Pow(g, flag==1 ? (P-1)/l : P-1-(P-1)/l); for(ll *p=a; p!=a+n; p+=l) { ll w=1; for(int k=0; k<m; k++) { ll t = w * p[k+m]%P; p[k+m]=(p[k]-t+P)%P; p[k]=(p[k]+t)%P; w=w*wn%P; } } } if(flag==-1) { ll inv=Pow(n, P-2); for(int i=0; i<n; i++) a[i]=a[i]*inv%P; } } void mul(ll *a, ll *b) { dft(a, 1); dft(b, 1); for(int i=0; i<n; i++) a[i]=a[i]*b[i]; dft(a, -1); } }using ntt::ini; using ntt::mul; int n, rev[N]; ll inv[N], fac[N], facInv[N]; ll f[N], a[N], b[N]; int main() { freopen("in","r",stdin); n=read(); inv[1]=1; fac[0]=facInv[0]=1; for(int i=1; i<=n; i++) { if(i!=1) inv[i] = (P-P/i)*inv[P%i]%P; fac[i] = fac[i-1]*i%P; facInv[i] = facInv[i-1]*inv[i]%P; } a[0]=1; b[0]=1; b[1]=n+1; for(int i=1; i<=n; i++) a[i] = (i&1 ? -1 : 1) * facInv[i]; for(int i=2; i<=n; i++) b[i] = (Pow(i, n+1)-1) * inv[i-1] %P * facInv[i] %P; ini(n+n+1); mul(a, b); ll ans=0; for(int i=0; i<=n; i++) ( ans += Pow(2, i)*fac[i]%P * a[i]%P )%=P; if(ans<0) ans+=P; printf("%lld", ans); } ```]

  • 相关阅读:
    什么是函数式编程
    红包算法
    laravel中查看执行的SQL语句
    身份证号信息后台匹配
    在函数内部访问外部的变量
    设计模式-观察者模式
    laravel查询构造器操作数据库
    linux根目录文件夹的作用
    关于laravel连接数据库报错
    设定起始日期,遍历到今天的日期
  • 原文地址:https://www.cnblogs.com/candy99/p/6648754.html
Copyright © 2020-2023  润新知