codeforces gym102471 C Dirichlet k-th root

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)=a1a2...ak=n,ai<mf(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)=kf(n)+Fk(n,n)
k ∗ f ( n ) = g ( n ) − F k ( n , n ) k*f(n)=g(n)-F^k(n,n) kf(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)=dn,if(k==1)1<d<nFk(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)=dn,d=nf(d)F2k(dn)

由于在算 f ( n ) f(n) f(n)之前, f ( 1 ) f(1) f(1) f ( n − 1 ) f(n-1) f(n1)已经计算出来了所以可以有类似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
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值