[hdu5628]Clarke and math(dirichlet卷积)

传送门
狄利克雷卷积定义:$$(fg)(n)=sum_{d|n}f(d)g({frac n d})$$狄利克雷卷积满足交换律:$$fg=gf$$结合律:$$(fg)h=f(gh)$$还有这么几个性质:$$fvarepsilon=f$$ $$f1=sum_{d|n}f(d)$$其中$$1(n)=1,varepsilon(n)=[n=1]$$我们做这个题就是用的上面那条,题目中的式子可以化成这样:$$1^k*f$$然后快速幂就好了。
代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read(){
    int x=0;char ch=' ';int f=1;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')f=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const int p=1e9+7;
int n,k;
ll a[100001];
void dirichlet(ll *ans,ll *f){
    memset(a,0,sizeof(a));
    for(int i=1;i*i<=n;i++){
        a[i*i]=(a[i*i]+ans[i]*f[i])%p;
        for(int j=i+1;j*i<=n;j++){
            a[i*j]=(a[i*j]+ans[i]*f[j])%p;
            a[i*j]=(a[i*j]+ans[j]*f[i])%p;
        }
    }
    for(int i=1;i<=n;i++)ans[i]=a[i];
}
ll f[100001],ans[100001],x[100001];
void ksm(){
    int b=k;
    while(b){
        if(b&1){
            dirichlet(ans,x);
        }
        dirichlet(x,x);
        b>>=1;
    }
}
void solve(){
    for(int i=1;i<=n;i++){
        f[i]=read();
        x[i]=1;
        ans[i]=0;
    }
    ans[1]=1;
    ksm();
    dirichlet(f,ans);
    for(int i=1;i<n;i++){
        printf("%lld ",f[i]);
    }
    printf("%lld
",f[n]);
}

int T;
int main(){
    T=read();
    while(T--){
        n=read();k=read();
        solve();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/stone41123/p/7605431.html