problem
给出 n , k n,k n,k 和数论函数 f ( i ) , i ∈ [ 1 , n ] f(i),i\in[1,n] f(i),i∈[1,n]。对于 ∀ i ∈ [ 1 , n ] \forall i\in[1,n] ∀i∈[1,n],请求出:
g ( i ) = ∑ i 1 ∣ i ∑ i 2 ∣ i 1 ∑ i 3 ∣ i 2 ⋯ ∑ i k ∣ i k − 1 f ( i k ) g(i)=\sum_{i_1|i}\sum_{i_2|i_1}\sum_{i_3|i_2}\cdots\sum_{i_{k}|i_{k-1}}f(i_k) g(i)=i1∣i∑i2∣i1∑i3∣i2∑⋯ik∣ik−1∑f(ik)
答案对 1 0 9 + 7 10^9+7 109+7 取模。
数据范围: 1 ≤ n , k ≤ 1 0 5 1\le n,k\le 10^5 1≤n,k≤105, 0 ≤ f ( i ) < 1 0 9 + 7 0\le f(i)<10^9+7 0≤f(i)<109+7。
solution
先介绍一下狄利克雷卷积,对于两个数论函数 f ( n ) f(n) f(n) 和 g ( n ) g(n) g(n),有:
( f ∗ g ) ( n ) = ∑ d ∣ n f ( d ) g ( n d ) (f*g)(n)=\sum_{d|n}f(d)g(\frac n d) (f∗g)(n)=d∣n∑f(d)g(dn)
求卷积的话,我们可以枚举约数 d d d,然后在倍数的地方加上相应的贡献,复杂度是 O ( n log n ) O(n\log n) O(nlogn) 的。
然后回到这道题来。
当 k = 1 k=1 k=1 的时候,有:
g 1 ( i ) = ∑ i 1 ∣ i f ( i 1 ) = ∑ i 1 ∣ i f ( i 1 ) 1 ( i i 1 ) = f ∗ 1 g_1(i)=\sum_{i_1|i}f(i_1)=\sum_{i_1|i}f(i_1)1(\frac{i}{i_1})=f*1 g1(i)=i1∣i∑f(i1)=i1∣i∑f(i1)1(i1i)=f∗1
其中 ∀ i ∈ N ∗ , 1 ( i ) = 1 \forall i\in N^*,1(i)=1 ∀i∈N∗,1(i)=1。
当 k = 2 k=2 k=2 时,有:
g 2 ( i ) = ∑ i 1 ∣ i g 1 ( i 1 ) = ∑ i 1 ∣ i g 1 ( i 1 ) 1 ( i i 1 ) = g 1 ∗ 1 = f ∗ 1 ∗ 1 g_2(i)=\sum_{i_1|i}g_1(i_1)=\sum_{i_1|i}g_1(i_1)1(\frac{i}{i_1})=g_1*1=f*1*1 g2(i)=i1∣i∑g1(i1)=i1∣i∑g1(i1)1(i1i)=g1∗1=f∗1∗1
那么不断递推,发现最终的答案就是 f ∗ 1 ∗ 1 ∗ ⋯ ∗ 1 f*1*1*\cdots*1 f∗1∗1∗⋯∗1(就是 f f f 和 k k k 个 1 1 1 卷起来)。
那么可以用快速幂优化这一过程,时间复杂度 O ( n log 2 n ) 。 O(n\log^2n)。 O(nlog2n)。
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define P 1000000007
using namespace std;
int n,k,F[N],I[N],ans[N],temp[N];
int add(int x,int y) {return x+y>=P?x+y-P:x+y;}
int dec(int x,int y) {return x-y< 0?x-y+P:x-y;}
int mul(int x,int y) {return 1ll*x*y%P;}
void Dirichlet(int *f,int *g){
memset(temp,0,sizeof(temp));
for(int i=1;i*i<=n;++i){
temp[i*i]=add(temp[i*i],mul(f[i],g[i]));
for(int j=i+1;i*j<=n;++j)
temp[i*j]=add(temp[i*j],add(mul(f[i],g[j]),mul(f[j],g[i])));
}
memcpy(f,temp,sizeof(temp));
}
void Solve(){
for(int i=1;i<=n;++i) I[i]=1,ans[i]=0;
ans[1]=1;
for(;k;k>>=1,Dirichlet(I,I))
if(k&1) Dirichlet(ans,I);
Dirichlet(ans,F);
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;++i) scanf("%d",&F[i]);
Solve();
for(int i=1;i<=n;++i) printf("%d%c",ans[i],i==n?'\n':' ');
}
return 0;
}