Codeforces Gym 102538A - Airplane Cliques(点减边容斥+FFT)

笑死,一共只写过 3 篇 Gym 的题解,其中一篇还与这篇相隔恰好 2 年。。。。。。

考虑什么样的点集满足条件,显然一个点集合法的充要条件是存在至少一个点距离这个点集中所有点都 \(\le\dfrac{x}{2}\)——这里出现 .5 什么的问题不大,只要在每条边中间加一个点即可。但是还是不方便计数,因为我们没法实现 \(\sum[V\ge 1]\)\(\sum V\) 的转化。不过发现符合上面的点一定在一个树上连通块中,根据经典点减边容斥,记 \(c_u\) 表示有多少个点离 \(u\) 距离 \(\le\dfrac{x}{2}\)\(d_e\) 表示有多少个点离 \(e\) 这条边的两个端点距离都 \(\le\dfrac{x}{2}\),那么对于一个 \(k\) 而言,答案就是 \(\sum\dbinom{c_u}{k}-\sum\dbinom{d_e}{k}\)

求解 \(c,d\) 是喜闻乐见的可以用点分治解决的问题。而后一部分相当于要求 \(\sum\limits_{i=1}^nb_i\dbinom{i}{k}\),把它变化一下就能得到 \(\sum\limits_{x-y=k}A_xB_y\) 的形式,FFT 即可。

时间复杂度 \(n\log^2n\)

const int MAXN=6e5;
const int INF=0x3f3f3f3f;
const int MOD=998244353;
const int pr=3;
const int ipr=332748118;
const int MAXP=1<<20;
int qpow(int x,int e){int ret=1;for(;e;e>>=1,x=1ll*x*x%MOD)if(e&1)ret=1ll*ret*x%MOD;return ret;}
int fac[MAXN+5],ifac[MAXN+5];
void init_fac(int n){
	for(int i=(fac[0]=ifac[0]=ifac[1]=1)+1;i<=n;i++)ifac[i]=1ll*ifac[MOD%i]*(MOD-MOD/i)%MOD;
	for(int i=1;i<=n;i++)fac[i]=1ll*fac[i-1]*i%MOD,ifac[i]=1ll*ifac[i-1]*ifac[i]%MOD;
}
int rev[MAXP+5];
void NTT(vector<int>&a,int len,int type){
	int lg=31-__builtin_clz(len);
	for(int i=0;i<len;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<lg-1);
	for(int i=0;i<len;i++)if(rev[i]<i)swap(a[i],a[rev[i]]);
	for(int i=2;i<=len;i<<=1){
		int W=qpow((type<0)?ipr:pr,(MOD-1)/i);
		for(int j=0;j<len;j+=i)for(int k=0,w=1;k<(i>>1);k++,w=1ll*w*W%MOD){
			int X=a[j+k],Y=1ll*a[(i>>1)+j+k]*w%MOD;
			a[j+k]=(X+Y)%MOD;a[(i>>1)+j+k]=(X-Y+MOD)%MOD;
		}
	}if(type<0){
		int iv=qpow(len,MOD-2);
		for(int i=0;i<len;i++)a[i]=1ll*a[i]*iv%MOD;
	}
}
vector<int>conv(vector<int>a,vector<int>b){
	int LEN=1;while(LEN<a.size()+b.size())LEN<<=1;
	a.resize(LEN,0);b.resize(LEN,0);NTT(a,LEN,1);NTT(b,LEN,1);
	for(int i=0;i<LEN;i++)a[i]=1ll*a[i]*b[i]%MOD;NTT(a,LEN,-1);
	return a;
}
int n,k,hd[MAXN+5],to[MAXN*2+5],nxt[MAXN*2+5],ec,c[MAXN+5];
void adde(int u,int v){
	to[++ec]=v;nxt[ec]=hd[u];hd[u]=ec;
	to[++ec]=u;nxt[ec]=hd[v];hd[v]=ec;
}
int mx[MAXN+5],siz[MAXN+5],cent,f[MAXN+5],vis[MAXN+5];
void findcent(int x,int f,int totsiz){
	siz[x]=1;mx[x]=0;
	for(int e=hd[x];e;e=nxt[e]){
		int y=to[e];if(y==f||vis[y])continue;findcent(y,x,totsiz);
		chkmax(mx[x],siz[y]);siz[x]+=siz[y];
	}chkmax(mx[x],totsiz-siz[x]);
	if(mx[x]<mx[cent])cent=x;
}
int t[MAXN+5];
void add(int x,int v){x++;for(int i=x;i<=n;i+=(i&(-i)))t[i]+=v;}
int query(int x){x++;int ret=0;for(int i=x;i;i&=(i-1))ret+=t[i];return ret;}
int dis[MAXN+5];vector<int>pt;
void getdis(int x,int f){
	for(int e=hd[x];e;e=nxt[e]){
		int y=to[e];if(y==f||vis[y])continue;dis[y]=dis[x]+1;
		getdis(y,x);
	}
}
void findpt(int x,int f){
	pt.pb(x);
	for(int e=hd[x];e;e=nxt[e]){
		int y=to[e];if(y==f||vis[y])continue;findpt(y,x);
	}
}
void divcent(int x){
	dis[x]=0;vis[x]=1;getdis(x,0);vector<int>all;all.pb(x);
	for(int e=hd[x];e;e=nxt[e]){
		int y=to[e];if(vis[y])continue;pt.clear();findpt(y,x);
		for(int z:pt)if(z<=n)add(dis[z],1);
		for(int z:pt)if(dis[z]<=k)f[z]-=query(k-dis[z]);
		for(int z:pt)if(z<=n)add(dis[z],-1);
		for(int z:pt)all.pb(z);
	}
	for(int z:all)if(z<=n)add(dis[z],1);
	for(int z:all)if(dis[z]<=k)f[z]+=query(k-dis[z]);
	for(int z:all)if(z<=n)add(dis[z],-1);
	for(int e=hd[x];e;e=nxt[e]){
		int y=to[e];if(vis[y])continue;cent=0;
		findcent(y,x,siz[y]);divcent(cent);
	}
}
int dfn[MAXN+5],edt[MAXN+5],tim,fa[MAXN+5],dep[MAXN+5],rid[MAXN+5];
void dfs0(int x,int f){fa[x]=f;rid[dfn[x]=++tim]=x;for(int e=hd[x];e;e=nxt[e]){int y=to[e];if(y==f)continue;dep[y]=dep[x]+1;dfs0(y,x);}edt[x]=tim;}
vector<int>vec[MAXN+5];
int main(){
#ifdef LOCAL
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
#endif
	scanf("%d%d",&n,&k);init_fac(MAXN);
	chkmin(k,n-1);for(int i=1,u,v;i<n;i++)scanf("%d%d",&u,&v),adde(u,i+n),adde(v,i+n);
	mx[0]=INF;findcent(1,0,2*n-1);divcent(cent);dfs0(1,0);
	for(int i=1;i<=n*2-1;i++)c[f[i]]=(c[f[i]]+1)%MOD;
	for(int i=1;i<=n;i++)vec[dep[i]].pb(dfn[i]);
	for(int i=0;i<=n*2-1;i++)sort(vec[i].begin(),vec[i].end());
	for(int i=2;i<=n*2-1;i++){
		int sum=f[i];
		if(dep[i]+k<=n*2-1){
			int L=lower_bound(vec[dep[i]+k].begin(),vec[dep[i]+k].end(),dfn[i])-vec[dep[i]+k].begin();
			int R=upper_bound(vec[dep[i]+k].begin(),vec[dep[i]+k].end(),edt[i])-vec[dep[i]+k].begin();
			sum-=R-L;
		}c[sum]=(c[sum]+MOD-1)%MOD;
	}
	vector<int>A(n+1),B(n+1),C;
	for(int i=1;i<=n;i++)A[i]=1ll*c[i]*fac[i]%MOD;
	for(int i=0;i<=n;i++)B[n-i]=ifac[i];
	C=conv(A,B);
	for(int i=1;i<=n;i++)printf("%d ",1ll*C[i+n]*ifac[i]%MOD);
	return 0;
}
posted @ 2022-12-23 20:12  tzc_wk  阅读(47)  评论(0编辑  收藏  举报