Codechef A Leisurely Journey

A Leisurely Journey

大厨最近接受了来自某个著名的烹饪学校的教职。这份工作还没有正式开始,所以大厨打算利用剩下的时间好好地度个假。有\(N\)座城市(编号\(1 ∼ N\)),由\(M\)条道路相连。对每个合法的\(i\),第\(i\)座城市内有\(L_i\)个旅游景点。大厨现在在城市\(1\),他将会在城市\(N\)教书。在他度假的每一天,他会进行如下活动中的某一种:

  • 走到一个编号比他目前所在城市要高的城市,要求这个城市与他目前所在的城市之间有道路连接。在假期结束的时候,大厨必须在城市\(N\)

  • 访问一个他目前所在城市中的旅游景点。大厨可以(在不同的时间)重复访问同一个旅游景点。

大厨还没有决定度多久的假。他有\(Q\)个询问,由序列\(D_1, D_2, . . . , D_Q\)描述。对每个询问(也就是对每个\(i\),其中\(1 ≤ i ≤ Q\)),他希望知道如果他的假期恰好长\(D_i\)天的话,不同的可能的度假计划的个数。由于这个数可能非常大,请你求出它模\(1, 000, 000, 007\)的值。

我们认为两个(持续时间相同的)度假计划不同,如果存在某一天使得大厨在这两个计划中做的事情不一样。访问两个不同的旅游景点也算不一样的事情。

\(1 ≤ N ≤ 4, 000\)\(1 ≤ M ≤ 10^5\)\(1 ≤ Q ≤ 500\)

题解

https://blog.csdn.net/qq_38609262/article/details/105586345

\(F_i(x)\)表示到达点ii的方案数关于时间的生成函数,显然有\(F_1(x)=\frac{1}{1-L_1x}\)\(F_i(x)=\frac{x\cdot\sum_{(j,i)\in E}F_j(x)}{1-L_ix}\)\(i>1\))。那么可以发现\(F_N(x)\)可以写成\(\frac{P(x)}{Q(x)}\)​的形式,其中\(\text{deg}(P(x))< N\)\(Q(x)=\prod_{i=1}^{N}(1-L_ix)\)。至于求出\(P(x)\),可以考虑先DP出\(F_N(x)\)的前\(N\)项系数,乘上\(Q(x)\)即可,DP时间复杂度为\(\mathcal O(NM)\)

现在每个询问即为给定\(k\),求出\([x^k]F_N(x)\)。如果直接用多项式取模加速常系数线性递推的经典算法,不仅单个询问复杂度为\(O(N\log N\log k)\),且因为模数不是NTT模数,需要任意模数FFT,因此常数非常大,不能通过。

可以发现现在给定了\(Q(x)\)的因子分解,可以尝试得到复杂度更优秀的算法。

考虑给\(L_i\)​排序,令去重后得到长度为\(d\)的数列\(p\),其中\(p_i\)​在\(L\)中出现了\(r_i\)​次。根据有理生成函数的一般展开定理,我们可以将\(F_N(x)\)表示为\(\sum_{i=1}^{d}\sum_{j=1}^{r_i}\frac{a_{i,j}}{(1-p_ix)^j}\)​​,那么\([x^k]F_N(x)=\sum_{i=1}^{d}\sum_{j=1}^{r_i}a_{i,j}\cdot \binom{k+j-1}{j-1}\cdot {p_i}^k\)。这样只需要快速幂就可以在\(\mathcal O(N\log k)\)的时间复杂度内处理单个询问。

现在难点在于得到这个分解,也即得到每个常数\(a_{i,j}\)​。令\(R_i(x)=\prod_{j\neq i}(1-p_jx)^{r_j}\)​,注意到通分后有\(P(x)=\sum_{i=1}^{d}\sum_{j=1}^{r_i}(a_{i,j}\cdot R_i(x)\cdot (1-p_ix)^{r_i-j})\)。那么有\(P(\frac{1}{p_i})=a_{i,r_i}\cdot \prod_{j\neq i}(1-\frac{p_j}{p_i})^{r_j}\)​,于是容易得到\(a_{i,r_i}\)​​。得到\(a_{i,r_i}\)​后从\(P(x)\)中减去对应项并整体除去一个\((1-p_ix)\)即可将\(r_i\)​减去\(1\),继续计算即可。这样分解时间复杂度为\(\mathcal O(N^2)\)

总时间复杂度为\(\mathcal O(NM+N^2+QN\log V)\)

CO int N=4e3+10;
int fac[N],ifac[N],w[N];
vector<int> to[N];
int f[N],p[N],q[N];
pair<int,int> buc[N];
vector<int> a[N];

int main(){
	int n=read<int>(),m=read<int>(),Q=read<int>();
	fac[0]=1;
	for(int i=1;i<=n;++i) fac[i]=mul(fac[i-1],i);
	ifac[n]=fpow(fac[n],mod-2);
	for(int i=n-1;i>=0;--i) ifac[i]=mul(ifac[i+1],i+1);
	for(int i=1;i<=n;++i) read(w[i]);
	for(int i=1;i<=m;++i){
		int x=read<int>(),y=read<int>();
		to[x].push_back(y);
	}
	
	f[1]=1,p[0]=n==1;
	for(int i=1;i<n;++i){
		for(int x=n;x>=1;--x){
			for(int y:to[x]) f[y]=add(f[y],f[x]);
			f[x]=mul(f[x],w[x]);
		}
		p[i]=f[n];
	}
	q[0]=1;
	for(int i=1;i<=n;++i)for(int j=n;j>=1;--j){
		p[j]=add(p[j],mul(p[j-1],mod-w[i]));
		q[j]=add(q[j],mul(q[j-1],mod-w[i]));
	}
	p[n]=0;
	
	sort(w+1,w+n+1);
	int num=0;
	for(int l=1,r;l<=n;l=r+1){
		for(r=l;r+1<=n and w[r+1]==w[l];++r);
		buc[++num]={w[l],r-l+1};
	}
	int all=n;
	for(int k=1;k<=num;++k){
		int w=buc[k].first,c=buc[k].second;
		int inv=fpow(w,mod-2);
		for(int i=1;i<=c;++i){
			int up=all-i+1;
			for(int j=up;j>=1;--j){
				q[j]=mul(q[j],mod-inv);
				q[j-1]=add(q[j-1],mod-q[j]);
			}
			for(int j=0;j<=up-1;++j) q[j]=q[j+1];
			q[up]=0;
		}
		all-=c;
		int sr=0;
		for(int i=all;i>=0;--i) sr=add(mul(sr,inv),q[i]);
		sr=fpow(sr,mod-2);
		a[k].resize(c+1);
		for(int i=c;i>=1;--i){
			int up=all-1+i,sl=0;
			for(int j=up;j>=0;--j) sl=add(mul(sl,inv),p[j]);
			a[k][i]=mul(sl,sr);
			for(int j=0;j<=all;++j) p[j]=add(p[j],mod-mul(q[j],a[k][i]));
			for(int j=up;j>=1;--j){
				p[j]=mul(p[j],mod-inv);
				p[j-1]=add(p[j-1],mod-p[j]);
			}
			for(int j=0;j<=up-1;++j) p[j]=p[j+1];
			p[up]=0;
		}
	}
	
	while(Q--){
		int64 t=read<int64>();
		int ans=0;
		for(int k=1;k<=num;++k){
			int w=buc[k].first,c=buc[k].second;
			int pwr=fpow(w,t%(mod-1)),fac=1;
			for(int i=1;i<=c;++i){
				ans=add(ans,mul(a[k][i],mul(fac,mul(ifac[i-1],pwr))));
				fac=mul(fac,(t+i)%mod);
			}
		}
		write(ans,'\n');
	}
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/autoint/p/13377729.html