• 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{xcdotsum_{(j,i)in E}F_j(x)}{1-L_ix})(i>1))。那么可以发现(F_N(x))可以写成(frac{P(x)}{Q(x)})​的形式,其中( ext{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(Nlog Nlog 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 inom{k+j-1}{j-1}cdot {p_i}^k)。这样只需要快速幂就可以在(mathcal O(Nlog k))的时间复杂度内处理单个询问。

    现在难点在于得到这个分解,也即得到每个常数(a_{i,j})​。令(R_i(x)=prod_{j eq 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 eq 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+QNlog 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,'
    ');
    	}
    	return 0;
    }
    
  • 相关阅读:
    JDBC原理
    练习 map集合被使用是因为具备映射关系 "进度班" "01" "张三" "进度班" "02" "李四" "J1701" "01" "王五" "J1701" "02" "王二" 此信息中,我们要怎样把上述信息装入集合中, 根据班级信息的到所有的所有信
    练习 HashSet 去重复
    集合练习 练习:每一个学生Student都有一个对应的归属地定义为String类型。学生属性:姓名,年龄 注意:姓名和年龄相同的视为同一个学生。保证学生的唯一性。 1、描述学生。 2、定义Map容器,将学生作为键,地址作为值存入集合中。 3、获取Map中的元素并进行排序。
    Java学习之Iterator(迭代器)的一般用法 (转)
    int 跟 Integer 的关系
    第十节 集合类Collection和Map
    类 Arrays StringBuilder 跟 StringBuffer 的异同 SimpleDateFormat
    数字转成字母型
    nginx之206异常
  • 原文地址:https://www.cnblogs.com/autoint/p/13377729.html
Copyright © 2020-2023  润新知