【HDU5628】Clarke and math-狄利克雷卷积+快速幂
测试地址:Clarke and math
题目大意:设
做法:此题需要用到狄利克雷卷积+快速幂。
定义两个算术函数
交换律:
结合律:
分配律:
那么再看我们要求的函数
这样一直推导下去,得到
注意如果用结构体传参会爆栈,直接用数组+指针传参就可以了。以及这题的格式要求行末不能有空格,但要有换行,注意一下就行了。
狄利克雷卷积的作用当然不只是做这种题,它为一堆有关莫比乌斯反演和杜教筛的式子提供了简明的记号,这个后面有时间再进行小结,这里就不再赘述了。
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mod 1000000007
#define ll long long
using namespace std;
int T,n,k;
ll f[100010],g[100010],s[100010],ss[100010],pro[100010];
void mult(ll *a,ll *b)
{
memset(s,0,sizeof(s));
for(int i=1;i*i<=n;i++)
{
s[i*i]=(s[i*i]+a[i]*b[i])%mod;
for(int j=i+1;i*j<=n;j++)
s[i*j]=(s[i*j]+a[i]*b[j]+a[j]*b[i])%mod;
}
for(int i=1;i<=n;i++) a[i]=s[i];
}
void power(ll *a,int p)
{
for(int i=1;i<=n;i++) ss[i]=a[i];
memset(pro,0,sizeof(pro));
pro[1]=1;
while(p)
{
if (p&1) mult(pro,ss);
mult(ss,ss);p>>=1;
}
for(int i=1;i<=n;i++) a[i]=pro[i];
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%lld",&f[i]);
g[i]=1;
}
power(g,k);
mult(f,g);
for(int i=1;i<=n;i++)
printf("%lld%c",f[i],(i==n)?'\n':' ');
}
return 0;
}