#4307. 前夕

题目描述

题解

好仙的题啊

考虑设交集大小至少为 $x$ 的个数为 $a_x$ ,则 $a_x=(_x^n)(2^{2^{n-x}}-1)$

然后我们考虑构造容斥系数 $f_x$ ,使得 $ans=\sum_{x=0}^nf_xa_x$

然后我们考虑到如果交集大小恰好为 $x$ 的最终要被算 $[x\%4=0]$ 遍,而对于 $\le x$ 的 $i$ ,它对于 $x$ 的贡献就是 $(_i^x)$ ,所以我们要使得 $[x\%4=0]=\sum_{k=0}^x(_k^x)f_x$

考虑二项式反演,将式子化为 $f_x=\sum_{k=0}^x(-1)^{x-k}(_k^x)[x\%4=0]$

考虑将 $[x\%4=0]$ 化开,这时候我们要用到很神奇的东西:单位复数根

记 $w_m$ 表示主 $m$ 次单位根,那么根据性质,我们可以得到 $[x\%m=0]=\sum_{i=0}^{m-1}(w_m^x)^i$

于是 $f_x=\sum_{k=0}^x(-1)^{x-k}(_k^x)\sum_{i=0}^{4-1}(w_4^x)^i$

把 $i$ 提前,得到 $f_x=\frac{(-1)^x}{4}\sum_{i=0}^{3}(1-w_4^i)^x$

于是我们可以 $O(nm)$处理出 $f_x$ ,然后计算答案

代码

#include <bits/stdc++.h>
using namespace std;
const int N=1e7+5,P=998244353;
int n,jc[N],ny[N],w[4],W[4],f[N],s=1;
int X(int x){return x>=P?x-P:x;}
int C(int x,int y){
    return 1ll*jc[x]*ny[y]%P*ny[x-y]%P;
}
int K(int x,int y){
    int z=1;
    for (;y;y>>=1,x=1ll*x*x%P)
        if (y&1) z=1ll*z*x%P;
    return z;
}
int main(){
    cin>>n;jc[0]=1;
    for (int i=1;i<=n;i++)
        jc[i]=1ll*i*jc[i-1]%P;
    ny[n]=K(jc[n],P-2);
    for (int i=n;i;i--)
        ny[i-1]=1ll*i*ny[i]%P;
    w[0]=1;w[1]=911660635;
    for (int i=2;i<4;i++)
        w[i]=1ll*w[i-1]*w[1]%P;
    for (int i=0;i<4;i++)
        W[i]=1,w[i]=X(1+P-w[i]);
    for (int i=0,F=1;i<=n;i++,F=P-F){
        for (int j=0;j<4;j++)
            f[i]=X(f[i]+W[j]);
        f[i]=748683265ll*F%P*f[i]%P;
        for (int j=0;j<4;j++)
            W[j]=1ll*W[j]*w[j]%P;
    }
    for (int i=n,v=2,u;~i;i--)
        u=1ll*C(n,i)*X(v-1+P)%P,
        s=X(s+1ll*u*f[i]%P),v=1ll*v*v%P;
    cout<<s<<endl;return 0;
}

猜你喜欢

转载自www.cnblogs.com/xjqxjq/p/12285481.html