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

本文通过复杂的数学公式推导,解析了一个特定数学问题的求解过程。该问题涉及数论中的积性函数、莫比乌斯反演等概念,并提供了一种有效的算法实现方案。

题意

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

分析

首先,根据 σ0(ij)=∑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=1n∑j∣m∑x∣i∑y∣j[(x,y)==1]=∑x=1n∑y∣m⌊nx⌋σ0(my)[(x,y)==1]=∑x=1n∑y∣m⌊nx⌋σ0(my)∑d∣x,d∣yμ(d)=∑d∣mμ(d)h(⌊nd⌋)f(md)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=1n⌊ni⌋h(n)=\sum\limits_{i=1}^{n}\lfloor\frac{n}{i}\rfloorh(n)=i=1ninf(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(⌊nd⌋)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!)
可以考虑枚举 ddd,因为 100100100 以内有 252525 个质数,因此最多有 2252^{25}225ddd
因为 fff 是个积性函数,可以快速求出。
每得到一个 ddd,除法分块得到 hhh,用哈希表储存值,这部分复杂度是 O(n34)O(n^{\frac{3}{4}})O(n43)
总的复杂度是 O(225+n34)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、付费专栏及课程。

余额充值