題目鏈接:
HDU 5628
題意:
給你
求
題解:
g(i)=∑i1|i∑i2|i1∑i3|i2⋯∑ik|ik−1f(ik) =∑i1|i∑i2|i1∑i3|i2⋯∑ik|ik−1f(ik)∗h(ik).
化爲
根據 狄利克雷卷積 滿足交換律和結合律, 先利用快速冪
每次
嗯,感覺有點難解釋。
就是兩個函數
可以寫成這樣:
然後可以發現原式的一層就是一次
又因爲狄利克雷卷積滿足交換律和結合律,所以
然後快速冪套一個狄利克雷卷積就可以了。
總時間複雜度就是
但是剛纔又想了一下。
發現了一個
我們可以考慮
可以發現,
然後我們發現
最後對於每一個
總時間複雜度就是
AC代碼:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod =1e9+7;
int n,k;
ll f[100010];
ll ans[100010];
ll tmp[100010],x[100010];
void dirichlet(ll *ans, ll *x){
memset(tmp,0,sizeof(tmp));
for(int i=1;i*i<=n;i++)
{
tmp[i*i] += ans[i]*x[i]%mod; if(tmp[i*i]>=mod) tmp[i*i]%=mod;
for(int j=i+1;i*j<=n;j++)
{
tmp[i*j] += ans[i]*x[j]%mod; if(tmp[i*j]>=mod) tmp[i*j]%=mod;
tmp[i*j] += ans[j]*x[i]%mod; if(tmp[i*j]>=mod) tmp[i*j]%=mod;
}
}
for(int i=1;i<=n;i++)
{
ans[i] = tmp[i];
}
}
void qpower(){
while(k)
{
if(k&1) dirichlet(ans,x);
k>>=1;
dirichlet(x,x);
}
dirichlet(ans,f);//乘 f
}
void solve()
{
for(int i=1;i<=n;i++)
{
scanf("%lld",&f[i]);
ans[i] = 0;
x[i] = 1;
}
ans[1] = 1;
qpower();
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&k);
solve();
for(int i=1;i<n;i++){
printf("%lld ",ans[i]);
}
printf("%lld\n",ans[n]);
}
return 0;
}