codeforces gym102471 C Dirichlet k-th root
题目:
有
g
=
f
k
g=f^k
g=fk,其中这里的乘指的是狄利克雷乘积。
现在,已知g求f(f不一定为积性函数)
题解:
有
g
(
n
)
=
f
k
(
n
)
g(n)=f^k(n)
g(n)=fk(n)
对于这种公式,首先我们应该想到两种方法,
一种是
g
1
k
(
n
)
=
f
(
n
)
g^{\frac{1}{k}}(n)=f(n)
gk1(n)=f(n),对于这种方法只要找到合适的数进行类似快速幂的卷积即可
另一种则是从公式推导,不过不变的肯定是用类似快速幂的思路将k优化到log(k)。
公式推导如下:
设
F
k
(
n
,
m
)
=
∑
a
1
∗
a
2
∗
.
.
.
∗
a
k
=
n
,
a
i
<
m
f
(
a
1
)
∗
f
(
a
2
)
∗
.
.
.
∗
f
(
a
k
)
F^k(n,m)=\sum_{a_1*a_2*...*a_k=n,a_i<m}f(a1)*f(a2)*...*f(ak)
Fk(n,m)=a1∗a2∗...∗ak=n,ai<m∑f(a1)∗f(a2)∗...∗f(ak)
g
(
n
)
=
f
k
(
n
)
=
k
∗
f
(
n
)
+
F
k
(
n
,
n
)
g(n)=f^k(n)=k*f(n)+F^k(n,n)
g(n)=fk(n)=k∗f(n)+Fk(n,n)
k
∗
f
(
n
)
=
g
(
n
)
−
F
k
(
n
,
n
)
k*f(n)=g(n)-F^k(n,n)
k∗f(n)=g(n)−Fk(n,n)
因此我们只要知道了
F
k
(
n
,
n
)
F^k(n,n)
Fk(n,n)就能把
f
(
n
)
f(n)
f(n)求出来了。
F
2
k
(
n
)
=
∑
d
∣
n
,
i
f
(
k
=
=
1
)
1
<
d
<
n
F
k
(
d
)
F
k
(
n
d
)
F^{2k}(n)=\sum_{d|n,if( k==1)1<d<n}{F^{k}(d)F^{k}(\frac{n}{d} )}
F2k(n)=d∣n,if(k==1)1<d<n∑Fk(d)Fk(dn)
F
2
k
+
1
(
n
)
=
∑
d
∣
n
,
d
≠
n
f
(
d
)
F
2
k
(
n
d
)
F^{2k+1}(n)=\sum_{d|n,d\neq n}{f(d)F^{2k}(\frac{n}{d} )}
F2k+1(n)=d∣n,d=n∑f(d)F2k(dn)
由于在算 f ( n ) f(n) f(n)之前, f ( 1 ) f(1) f(1)到 f ( n − 1 ) f(n-1) f(n−1)已经计算出来了所以可以有类似dp转移进行递推
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+5;
const int mod=998244353;
#define pb push_back
#define fi first
#define se second
#define all(x) (x).begin(),(x).end()
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,a,n) for (int i=n;i>=a;i--)
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
#define rint register int
typedef long long ll;
typedef double db;
typedef vector<int> vi;
typedef pair<int,int> pii;
ll qpow(ll a,ll b){ll ans=1;a%=mod;assert(b>=0);for(;b;b>>=1){if(b&1)ans=ans*a%mod;a=a*a%mod;}return ans;}
ll gcd(ll a,ll b){return b>0?gcd(b,a%b):a;}
int n,m,T;
int g[maxn],nxt[maxn];
int f[maxn];
vi v[maxn];
int cnt;
int F[65][maxn];
int main() {
// read(n),read(m);
scanf("%d%d",&n,&m);
// n=1e5;
// m=(1<<29)-1;
for(int i=2;i<=n;++i){
for(rint j=i+i;j<=n;j+=i){
v[j].pb(i);
}
}
// for(int i=1;i<=n;++i) g[i]=i;
// for(rint i=1;i<=n;++i) read(g[i]);
for(int i=1;i<=n;i++) scanf("%d",&g[i]);
int inv=qpow(m,mod-2);
f[1]=1;
int temp=m;
int tot=0;
while(temp){
nxt[++tot]=temp;
if(temp&1){
--temp;
}else{
temp>>=1;
}
}
int res=0;
for(int i=1;i<=tot;i++) F[i][1]=1;
for(int i=2;i<=n;++i){
for(int t=tot-1;t>=1;--t){
res=0;
for(int x:v[i]){
if(nxt[t]&1){
res=(res+1ll*F[t+1][x]*f[i/x])%mod;
}else{
res=(res+1ll*F[t+1][x]*F[t+1][i/x])%mod;
}
}
if(nxt[t]&1){
res=(res+1ll*F[t+1][i]*f[i/i]%mod)%mod;
}else{
res=(res+2ll*F[t+1][i]*F[t+1][i/i]%mod)%mod;
}
F[t][i]=res;
}
f[i]=(1ll*g[i]-F[1][i]+mod)%mod;
f[i]=1ll*f[i]*inv%mod;
F[tot][i]=f[i];
for(int t=tot-1;t>=1;t--){
F[t][i]=(F[t][i]+1ll*nxt[t]*f[i]%mod)%mod;
}
}
for(int i=1;i<=n;++i){
// print(f[i]);
// print(" ");
printf("%d%c",f[i]," \n"[i==n]);
}
// cout<<cnt<<"\n";
return 0;
}
/*
5 10000
1 40000 20000 799970000 30000
1 12 6 63 9
5 4
1 16 8 116 12
*/