[牛客挑战赛46E] 反演(莫比乌斯反演)

题意

在这里插入图片描述
在这里插入图片描述

分析

首先,根据 σ 0 ( i j ) = ∑ x ∣ i ∑ y ∣ j [ ( x , y ) = = 1 ] \sigma_0(ij) = \sum\limits_{x|i}\sum\limits_{y|j}[(x, y) == 1] σ0(ij)=xiyj[(x,y)==1],有
F ( m , n ) = ∑ i = 1 n ∑ j ∣ m ∑ x ∣ i ∑ y ∣ j [ ( x , y ) = = 1 ] = ∑ x = 1 n ∑ y ∣ m ⌊ n x ⌋ σ 0 ( m y ) [ ( x , y ) = = 1 ] = ∑ x = 1 n ∑ y ∣ m ⌊ n x ⌋ σ 0 ( m y ) ∑ d ∣ x , d ∣ y μ ( d ) = ∑ d ∣ m μ ( d ) h ( ⌊ n d ⌋ ) f ( m d ) F(m, n) \\= \sum\limits_{i=1}^{n}\sum\limits_{j|m}\sum\limits_{x|i}\sum\limits_{y|j}[(x,y)==1]\\=\sum\limits_{x=1}^{n}\sum\limits_{y|m}\lfloor\frac{n}{x}\rfloor \sigma_0(\frac{m}{y})[(x,y)==1]\\=\sum\limits_{x=1}^{n}\sum\limits_{y|m}\lfloor\frac{n}{x}\rfloor \sigma_0(\frac{m}{y})\sum\limits_{d|x,d|y}\mu(d)\\=\sum\limits_{d|m}\mu(d)h(\lfloor\frac{n}{d}\rfloor )f(\frac{m}{d}) F(m,n)=i=1njmxiyj[(x,y)==1]=x=1nymxnσ0(ym)[(x,y)==1]=x=1nymxnσ0(ym)dx,dyμ(d)=dmμ(d)h(dn)f(dm)
其中, h ( n ) = ∑ i = 1 n ⌊ n i ⌋ h(n)=\sum\limits_{i=1}^{n}\lfloor\frac{n}{i}\rfloor h(n)=i=1nin f ( n ) = ∑ d ∣ n σ 0 ( d ) f(n)=\sum\limits_{d|n}\sigma_0(d) f(n)=dnσ0(d)
那么,我们要求的是 F ( m ! , n ) F(m!,n) F(m!,n),即 ∑ d ∣ m ! μ ( d ) h ( ⌊ n d ⌋ ) f ( m ! d ) \sum\limits_{d|m!}\mu(d)h(\lfloor\frac{n}{d}\rfloor )f(\frac{m!}{d}) dm!μ(d)h(dn)f(dm!)
可以考虑枚举 d d d,因为 100 100 100 以内有 25 25 25 个质数,因此最多有 2 25 2^{25} 225 d d d
因为 f f f 是个积性函数,可以快速求出。
每得到一个 d d d,除法分块得到 h h h,用哈希表储存值,这部分复杂度是 O ( n 3 4 ) O(n^{\frac{3}{4}}) O(n43)
总的复杂度是 O ( 2 25 + n 3 4 ) O(2^{25}+n^{\frac{3}{4}}) O(225+n43)

代码

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
typedef long long LL;

void debug_out(){
    cerr << endl;
}
template<typename Head, typename... Tail>
void debug_out(Head H, Tail... T){
    cerr << " " << to_string(H);
    debug_out(T...);
}
#ifdef local
#define debug(...) cerr<<"["<<#__VA_ARGS__<<"]:",debug_out(__VA_ARGS__)
#else
#define debug(...) 55
#endif

const int mod = 998244353, N = 1e7 + 5;
LL n;
int p[26], cnt, power[105], inv[N], ans, tot = 1;
gp_hash_table<int, int> f;
int h(LL n){
	if(f[n]) return f[n];
	LL s = 0;
	for(LL l = 1, r; l <= n; l = r + 1){
		r = n / (n / l);
		s += (r - l + 1) * (n / l) % mod;
		if(s >= mod) s -= mod;
	}
	return f[n] = s;
}
void dfs(int pos, LL x, int mu, int sum){
	if(x > n) return;
	if(pos == cnt + 1){
		ans = (ans + (LL)mu * h(n / x) * sum % mod) % mod;
		return;
	}
	dfs(pos + 1, x, mu, sum);
	dfs(pos + 1, x * p[pos], -mu, (LL)sum * inv[(power[p[pos]] + 2) * (power[p[pos]] + 1) / 2] % mod * ((power[p[pos]] + 1) * power[p[pos]] / 2) % mod);
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int m;
	inv[1] = 1;
	for(int i = 2; i <= 10000; i++) inv[i] = (LL)inv[mod % i] * (mod - mod / i) % mod;
	cin >> n >> m;
	for(int i = 2; i <= m; i++){
		int ok = 1;
		for(int j = 2; j <= i / j; j++) if(i % j == 0) ok = 0;
		if(ok){
			p[++cnt] = i;
			int t = m;
			while(t){
				power[i] += t / i;
				t /= i;
			}
			tot = (LL)tot * ((power[i] + 2) * (power[i] + 1) / 2) % mod;
		}
	}
	dfs(1, 1, 1, tot);
	cout << (ans + mod) % mod << '\n';
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值