LOJ 前夕

解题方法:

设F(x)表示至少有i种技能的方案数

显然有:$F(x)=C_{n}^{x} imes 2^{2^{n-x}}$

我们构造容斥函数$f(x)$,令$Ans=sum f(x) imes F(x)$

题目要求的是所有技能数恰为4k的方案数,所以能得出$[4|x]=sumlimits_{i=0}^{x} C_{x}^{i}*f[i]$

二项式反演得:$f[x]=sumlimits_{i=0}^{x} (-1)^{x-i} imes C_{x}^{i}*[4|i]$

$[4|i]$这个东西是可以转化成单位根的式子的,$[4|i]=frac{1}{4}sumlimits_{j=0}^{3}omega^{ij}$

带进去:$f[x]=frac{1}{4}sumlimits_{i=0}^{x} (-1)^{x-i} imes C_{x}^{i} sumlimits_{j=0}^{3} omega^{ij}$

$=frac{1}{4}sumlimits_{j=0}^{3} sumlimits_{i=0}^{x} (-1)^{x-i} imes C_{x}^{i}  omega^{ij}$

 $=frac{1}{4}sumlimits_{j=0}^{3}(omega^{j}-1)^{x}$

我们成功的求出了容斥函数

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dwn(i,a,b) for(int i=a;i>=b;i--)
#define MAXN 10000005
using namespace std;
int read(){
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9' || ch<'0') ch=getchar();
	while('0'<=ch && ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	return x;
}
typedef long long  ll;
const ll mod=998244353;
int n;
ll ksm(ll x,ll y){
	ll res=1;
	while(y){
		if(y&1) res=(res*x)%mod;
		x=(x*x)%mod;
		y>>=1;
	}
	return res;
}
ll jc=1,ans,inv1=mod-1,a[MAXN],F,now=1,sum,tmp,inv[MAXN],Wn[4],w[4],inv4,f; 
void pd(){
	if(tmp==1) tmp=inv1;
	else tmp=1;
}
ll C(ll x,ll y){
	return (jc*inv[x]%mod)*inv[y-x]%mod;
}
int main(){
    n=read(); 
	inv[1]=1; inv[0]=1; inv4=ksm(4,mod-2);
	a[n]=2; w[0]=w[1]=w[2]=w[3]=1;
    rep(i,2,n) inv[i]=((-(mod/i)*inv[mod%i])%mod+mod)%mod,jc=(jc*i)%mod;
    rep(i,2,n) inv[i]=inv[i-1]*inv[i]%mod;
    Wn[0]=0; Wn[1]=ksm(3,(mod-1)/4)-1; Wn[2]=ksm(3,(mod-1)/2)-1; Wn[3]=ksm(3,((mod-1)/4)*3)-1;
    dwn(i,n-1,0) a[i]=(a[i+1]*a[i+1])%mod;
    rep(i,0,n) a[i]=(a[i]-1+mod)%mod;
    rep(i,0,n){
    	F=a[i]*C(i,n)%mod;
    	f=inv4*((w[0]+w[1]+w[2]+w[3])%mod)%mod; 
    	ans=(ans+F*f)%mod;
    	rep(j,0,3) w[j]=(w[j]*Wn[j])%mod;//,cout<<w[j]<<" ";cout<<endl;
	}
	printf("%lld",(ans+1)%mod);
	return 0;
}
原文地址:https://www.cnblogs.com/handsome-zlk/p/14504151.html