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