设f,g为两个数论函数,那么规定 (f∗g)(n)=∑d|n f(d)g(n/d)为f,g的Dirichlet卷积
该运算满足 交换律、结合律、分配律。
并且存在一个幺元e,使得e*f = f。 当i = 1 时 e[i] = 1,i != 1 时 e[i] = 0;
另函数 h[i] 恒等于 1.
g(i)=∑i1∣i∑i2∣i1∑i3∣i2⋯∑ik∣ik−1f(ik) = ∑i1∣i∑i2∣i1∑i3∣i2⋯∑ik∣ik−1f(ik) *h(ik) .
化为Dirichlet卷积形式,g(i) = (f*h^k)(i)
由于满足交换律, 先利用快速幂h^k。最后再拿h^k的结果与f卷积(注意,两个函数卷积的结果是函数,而不是值)
每次Dirichlet卷积的 复杂度为 O(n*logn),进行logk次卷积计算,单组复杂度O(n*logn*logk).
/*************************************************************************
> File Name: hdu5628.cpp
> Author: TechMonster
> Mail: 928221136@qq.com
> Created Time: 三 7/13 16:20:40 2016
************************************************************************/
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
#define MS(x,y) memset(x,y,sizeof(x))
typedef long long LL;
const int N = 100010;
const LL M = 1e9+7;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) {a += b;if(a > M) a%= M;}
int n,k;
LL f[N],ans[N],tem[N],x[N];
void Dirichlet(LL *ans, LL *x)//Dirichlet卷积
{
MS(tem,0);
for(int i = 1; i*i <= n; ++i)
{
gadd(tem[i*i],ans[i]*x[i]%M);
for(int j = i+1; j*i <= n; ++j)
{
gadd(tem[i*j],ans[i]*x[j]%M);
gadd(tem[i*j],ans[j]*x[i]%M);
}
}
for(int i = 1; i <= n; ++i) ans[i] = tem[i];
}
void calc()
{
while(k) //快速幂
{
if(k&1) Dirichlet(ans,x);
Dirichlet(x,x);
k>>=1;
}
Dirichlet(ans,f); //乘f
}
void solve()
{
scanf("%d%d",&n,&k);
for(int i = 1; i <= n; ++i)
{
scanf("%lld",&f[i]);
ans[i] = 0; x[i] = 1;//初始ans为幺元,x为恒等于1的函数
}
ans[1] = 1;
calc();
for(int i = 1; i < n; ++i) printf("%lld ",ans[i]);
printf("%lld\n",ans[n]);
}
int main()
{
int T;scanf("%d",&T);while(T--)solve();
return 0;
}