1. 程式人生 > 實用技巧 >[2019 EC-Final] C. Dirichlet kk-th root (狄利克雷卷積的性質+快速冪)

[2019 EC-Final] C. Dirichlet kk-th root (狄利克雷卷積的性質+快速冪)

題意:

給定n和k,給定一個數論函式\(g\)的前n項,找到這樣一個數論函式\(f\)使得\(f^k=g\)(在狄利克雷卷積意義下,mod p意義下)(p為質數),列印\(f\)的前n項。(保證\(g(1)=1\)

解法:

\(g(1)=1\)的條件下可以由\(f^k=g\)推出\(f=g^{1/k}\)(\(1/k是k的逆元\)),然後就可以利用套了快速冪的卷積在\(O(logN*logN*N)\)的時間內求出

程式碼:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=1e5+5;
const ll mod = 998244353;
ll fp(ll b,ll p){
    ll ans=1;
    while(p){
        if(p&1)ans=ans*b%mod;
        b=b*b%mod;
        p>>=1;
    }
    return ans;
}
ll a[maxn],ans[maxn];
ll n,k;
ll temp[maxn];
void mul(ll *a,ll *b){//n*logn
    for(ll i=1;i<=n;i++)temp[i]=0;
    for(ll i=1;i<=n;i++){
        for(ll j=1;i*j<=n;j++){
            temp[i*j]=(temp[i*j]+a[i]*b[j])%mod;
        }
    }
    for(ll i=1;i<=n;i++)a[i]=temp[i];
}
void solve(){
    ans[1]=1;
    while(k){
        if(k&1)mul(ans,a);
        mul(a,a);
        k>>=1;
    }
}
int main () {
    scanf("%lld%lld",&n,&k);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
    }
    k=fp(k,mod-2);
    solve();
    for(int i=1;i<=n;i++){
        if(i>1)printf(" ");
        printf("%lld",ans[i]);
    }
}