LGP8290题解

场外选手再次口胡

这种东西如果是链就很好做,并且有链的部分分。。。那么就照着这个方向想想吧。

考虑计算对于一个序列,全部都被填了数字的方案数。

容易发现枚举最大值有很简单的 \(O(nK)\) 做法:

\[\sum_{x=0}^{\infty}\prod_{i=1}^{n}(\min(x+K,r_i)-\max(x,l_i))-\prod_{i=1}^{n}(\min(x+K-1,r_i)-\max(x,l_i)) \]

两部分差的不多,所以只用考虑一边。

并且容易发现这个是点权的 \(0\) 次和,所以先暂且不考虑 \(1\) 次和,做法可以凭感觉确定是类似的(

容易发现,可以把 \(l_i\)\(r_i\) 分成四类贡献。

然后,我们将所有的 \(l_i,r_i,l_i+K,r_i+K,l_i-K,r_i-K\) 全部拉出来排序,每个 \(x\) 能够对应排序后的一段。然后容易发现,一段对一个节点的贡献是固定的。

也就是说,如果 \(x\) 在离散化后的某个区间上,那么一个节点对其的贡献一定是一个和 \(x\) 有关的一次多项式。

于是我们枚举 \(x\) 在哪一段,问题就变成了先对每一段计算多项式,然后计算 一棵树上所有路径的多项式之积之和

这种典中典问题当然是用点分治最好。。。但是模数不是 \(998244353\)

考虑 NTT 的本质是插值。于是我们就插值。可以知道答案多项式一定是 \(O(n)\) 次的,于是代入 \(O(n)\) 跑一遍拉插就行了。

一棵树上所有路径的点权之积之和,这种典中典问题可以 DP \(O(n)\) 解决掉。

然后,求 \(\sum_{i=0}^{x}F(x)\) 这种东西,稍微推一下式子:

\[\sum_{i=0}^{x}\sum_{k=0}^{n}f_ki^k \]

\[\sum_{k=0}^{n}f_k\sum_{i=0}^{x}i^k \]

众所周知后面是和 \(k\) 有关的多项式,在最开始时预处理即可。

复杂度 \(O(n^3)\)

下面是一个复杂度正确但是写了一整天而且常数巨大被卡飞的算法:

#include<algorithm>
#include<cstdio>
typedef unsigned ui;
const ui M=205,mod=1e9+7,inv2=500000004,Inv2=500000003;
ui n,K,cnt,h[M],l[M],r[M],dp1[M],dp2[M],val1[M],val2[M];bool vis[M];
ui len,lsh[M<<2];ui q[M<<1],p[M<<1];ui inv[M];ui ans1,ans2;ui lf[M],lg[M],f[M][3],g[M][3];ui ifac[M<<1];
struct Edge{
	ui v,nx;
}e[M<<1];
inline void Add(const ui&u,const ui&v){
	e[++cnt]=(Edge){v,h[u]};h[u]=cnt;
	e[++cnt]=(Edge){u,h[v]};h[v]=cnt;
}
inline ui calc(ui*F,const ui&x){
	return((1ull*F[2]*x+F[1])%mod*x+F[0])%mod;
}
namespace cal{
	ui y[M<<1],q[M<<1],p[M<<1],val[M<<1];
	inline ui calc(const ui&n,const ui&X){
		ui ans(0);q[0]=p[n+1]=1;
		for(ui i=1;i<=n;++i)val[i]=1ull*y[i]*ifac[i-1]%mod*(n-i&1?mod-ifac[n-i]:ifac[n-i])%mod;
		for(ui i=1;i<=n;++i)q[i]=1ull*q[i-1]*(X+mod-i)%mod;for(ui i=n;i>=1;--i)p[i]=1ull*p[i+1]*(X+mod-i)%mod;
		for(ui i=1;i<=n;++i)ans=(ans+1ull*q[i-1]*p[i+1]%mod*val[i])%mod;return ans;
	}
}
inline void calc(const ui&u,const ui&fa,ui&ans1,ui&ans2){
	dp1[u]=val1[u];dp2[u]=val2[u];ans1=(ans1+val1[u])%mod;ans2=(ans2+val2[u])%mod;
	for(ui v,E=h[u];E;E=e[E].nx)if((v=e[E].v)^fa){
		calc(v,u,ans1,ans2);if(!vis[v]||!vis[u])continue;
		ans1=(ans1+1ull*dp1[u]*dp1[v])%mod;
		ans2=(ans2+1ull*dp2[u]*dp1[v]+1ull*dp1[u]*dp2[v])%mod;
		dp1[u]=(dp1[u]+1ull*val1[u]*dp1[v])%mod;
		dp2[u]=(dp2[u]+1ull*val2[u]%mod*dp1[v]+1ull*val1[u]*dp2[v])%mod;
	}
}
inline void Solve(const ui&K,const bool&typ,const ui&lim){
	ui A(0),B(0);len=0;
	for(ui i=1;i<=n;++i){
		if(r[i]+K<=lim)lsh[++len]=r[i]+K;if(r[i]<=lim)lsh[++len]=r[i];
		if(l[i]+K<=lim)lsh[++len]=l[i]+K;if(l[i]<=lim)lsh[++len]=l[i];
	}
	lsh[++len]=0;lsh[++len]=lim;
	std::sort(lsh+1,lsh+len+1);len=std::unique(lsh+1,lsh+len+1)-lsh-1;
	for(ui i=1;i<len;++i){
		const ui&x=lsh[i+1];
		for(ui u=1;u<=n;++u){
			ui*F=f[u],*G=g[u];F[0]=F[1]=G[0]=G[1]=G[2]=0;
			if(x<=l[u]||r[u]+K<x){
				vis[u]=false;lf[u]=lg[u]=1;continue;
			}
			vis[u]=true;lf[u]=2;lg[u]=3;
			if(x<=r[u]){
				F[1]=(F[1]+1)%mod;
				G[2]=(G[2]+inv2)%mod,G[1]=(G[1]+inv2)%mod;
			}
			else{
				F[0]=(F[0]+r[u])%mod;
				G[0]=(G[0]+1ull*r[u]*(r[u]+1)%mod*inv2)%mod;
			}
			if(x<=l[u]+K){
				F[0]=(F[0]+mod-l[u])%mod;
				G[0]=(G[0]+1ull*l[u]*(l[u]+1)%mod*Inv2)%mod;
			}
			else{
				F[1]=(F[1]+mod-1)%mod,F[0]=(F[0]+K)%mod;
				G[2]=(G[2]+Inv2)%mod,G[1]=(G[1]+1ull*inv2*(2*K-1))%mod,G[0]=(G[0]+1ull*K*(K-1)%mod*Inv2)%mod;
			}
		}
		const ui&L=lsh[i],&R=lsh[i+1];ui m1(1),m2(1),qa,pb;
		for(ui i=1;i<=n;++i)m1+=lf[i]-1,m2+=lg[i]-1;
		for(ui i=1;i<=m2+1;++i){
			for(ui u=1;u<=n;++u)val1[u]=vis[u]?calc(f[u],i):0,val2[u]=vis[u]?calc(g[u],i):0;
			qa=pb=0;calc(1,0,qa,pb);q[i]=qa;p[i]=pb;
		}
		for(ui i=1;i<=m1+1;++i)cal::y[i]=(cal::y[i-1]+q[i])%mod;A=(A+cal::calc(m1+1,R)+mod-cal::calc(m1+1,L))%mod;
		for(ui i=1;i<=m2+1;++i)cal::y[i]=(cal::y[i-1]+p[i])%mod;B=(B+cal::calc(m2+1,R)+mod-cal::calc(m2+1,L))%mod;
	}
	if(!typ)ans1=A,ans2=B;else ans1=(ans1+mod-A)%mod,ans2=(ans2+mod-B)%mod;
}
signed main(){
	scanf("%u%u",&n,&K);
	ifac[0]=ifac[1]=1;
	for(ui i=2;i<=(n*2+5);++i)ifac[i]=1ull*(mod-mod/i)*ifac[mod%i]%mod;
	for(ui i=1;i<=(n*2+5);++i)ifac[i]=1ull*ifac[i-1]*ifac[i]%mod;
	for(ui i=1;i<=n;++i)scanf("%u%u",l+i,r+i),--l[i];for(ui u,v,i=1;i<n;++i)scanf("%u%u",&u,&v),Add(u,v);
	Solve(K+1,0,1e9);Solve(K,1,1e9-1);printf("%u\n%u",ans1,ans2);
}
posted @ 2022-04-19 19:49  Prean  阅读(26)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};