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;
}