LOJ6358 前夕

上来4的倍数又要交集恰好 单位根反演+二项式反演定了(

具体推柿子放下面了qwq

$g(n) = sum_{i=n}^N f(i) inom{i}{n} \g(n) = inom{N}{n} (2^{2^{N-n}}-1) \f(n) = sum_{i=n}^N inom{i}{n} (-1)^{n-i} g(i) \ ans = sum_{n=0}^N [n\%4==0] f(n) \ans= sum_{n=0}^N sum_{j=0}^3 w_4^{nj} f(n) \ans= sum_{n=0}^N sum_{i=n}^N sum_{j=0}^3 w_4^{nj}(-1)^{i-n}g(i)inom{i}{n}\ans= sum_{i=0}^N (-1)^i g(i) sum_{n=0}^i sum_{j=0}^3 w_4^{nj} (-1)^n inom{i}{n}\ans= sum_{i=0}^N (-1)^i g(i) sum_{j=0}^3 (-w_4^{j}+1)^i$

里面那个-1是为了方便处理空集(不然空集可能加上可能被容斥掉了x)

然后憨憨hywn发现自己不会快速求$2^{2^{N-n}}$ 被大爹suncb教了一发...直接每次平方就好了...我可能是个sbx

于是就做完啦

(第一次推完这么长柿子好感动)

//Love and Freedom.
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define ll long long
#define inf 20021225
#define mdn 998244353
#define G 3
#define inv4 748683265ll
using namespace std;
int read()
{
    int s=0,t=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')    t=-1; ch=getchar();}
    while(ch>='0' && ch<='9')    s=s*10+ch-'0',ch=getchar();
    return s*t;
}
int ksm(int bs,int mi)
{
    int ans=1;
    while(mi)
    {
        if(mi&1)    ans=1ll*ans*bs%mdn;
        bs=1ll*bs*bs%mdn; mi>>=1; 
    }
    return ans;
}
#define N 10000001
int w[4][2],fac[N],inv[N],g[N];
int C(int n,int m){return n<m?0:1ll*fac[n]*inv[m]%mdn*inv[n-m]%mdn;}
int main()
{
    int n=read(); int Wn=ksm(G,(mdn-1)/4); int ans=0;
    for(int i=0;i<4;i++)    w[i][0]=1;
    for(int i=0;i<4;i++)    w[i][1]=(-ksm(Wn,i)+1+mdn)%mdn;
    fac[0]=1;
    for(int i=1;i<=n;i++)    fac[i]=1ll*fac[i-1]*i%mdn;
    inv[n]=ksm(fac[n],mdn-2);
    for(int i=n;i;i--)     inv[i-1]=1ll*inv[i]*i%mdn;
    g[n]=2;
    for(int i=n;i;i--)    g[i-1]=1ll*g[i]*g[i]%mdn;
    for(int i=0;i<=n;i++)
    {
        int val=0;
        for(int j=0;j<4;j++)
            (val+=w[j][0])%=mdn,w[j][0]=1ll*w[j][0]*w[j][1]%mdn;
        (ans+=1ll*(g[i]-1)*C(n,i)%mdn*(i&1?mdn-1:1)%mdn*val%mdn*inv4%mdn)%=mdn;
    }
    printf("%d
",ans+1);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/hanyuweining/p/12045723.html