P6055 [RC-02] GCD 另解

P6055 [RC-02] GCD 另解

首先,使用你强大的注意力发现,好像对于 \(p,q\) 的枚举很像是在枚举 \(\gcd(p,q)=j\) 的对,将其还原回去,然后考虑对于一对 \(p,q\),考虑不再枚举 \(j\),那么式子可以化成 \([\gcd(i,\gcd(p,q))=1]\)。也就是说,要求解的东西是,有多少三元组 \((i,j,k)\) 满足 \(\gcd(i,j,k)=1\)\(i,j,k\in [1,n]\)。我们设这个答案是 \(S(n)=\sum_{d=1}^n\mu(d)\lfloor \frac{n}d\rfloor^3\)

一般做法考虑杜教筛 \(\mu\),我们直接杜教筛 \(S\)其实感觉已经完全不是杜教筛了。

这好像不是数论函数前缀和吧!

但是其实我们只要满足(下式显然成立)

\[ \begin{aligned} g(1)S(n) & = \sum_{i=1}^n g(i)S\left(\left\lfloor\frac{n}{i}\right\rfloor\right) - \sum_{i=2}^n g(i)S\left(\left\lfloor\frac{n}{i}\right\rfloor\right) \\ \end{aligned} \]

中的 \(\sum_{i=1}^n g(i)S(\lfloor \frac{n}{i}\rfloor)\) 可以快速计算,以及 \(g(i)\) 的前缀和可以快速计算,那么就可以使用杜教筛来进行计算,\(S\) 可以不必是前缀和。

我们此处取 \(g(i)=1\),显然,\(g(i)\) 的前缀和可以快速计算。那么 \(\sum_{i=1}^n g(i)S(\lfloor \frac{n}{i}\rfloor)\) 能快速计算吗?

我们发现 \(\sum_{i=1}^n g(i)S(\lfloor \frac{n}{i}\rfloor)=n^3\),因为 \(i\) 的枚举相当于将 \((i,j,k)\) 三元组按照 \(\gcd(i,j,k)\) 的值进行分类,每个三元组都会在其 \(\gcd\) 处被统计一次,那么这部分也搞定了,我们考虑形式证明此结论:

\[\begin{aligned} & \sum_{i=1}^n g(i)S(\lfloor \frac{n}{i}\rfloor)\\ =& \sum_{i=1}^n \sum_{a=1}^{\lfloor \frac{n}{i}\rfloor} \sum_{b=1}^{\lfloor \frac{n}{i}\rfloor} \sum_{c=1}^{\lfloor \frac{n}{i}\rfloor} [\gcd(a,b,c)=1] \\ =& \sum_{i=1}^n \sum_{a=1}^{n} \sum_{b=1}^{n} \sum_{c=1}^{n} \left[\gcd\left(\frac{a}i,\frac{b}i,\frac{c}i\right)=1\right][i|a][i|b][i|c] \\ =& \sum_{i=1}^n \sum_{a=1}^{n} \sum_{b=1}^{n} \sum_{c=1}^{n} [\gcd(a,b,c)=i][i|a][i|b][i|c] \\ =& \sum_{i=1}^n \sum_{a=1}^{n} \sum_{b=1}^{n} \sum_{c=1}^{n} [\gcd(a,b,c)=i] \end{aligned} \]

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll P=998244353,B=1000;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace __gnu_pbds;
unordered_map<int,int> cache;
inline int add(ll a,ll b){return (a+b>=P?a+b-P:a+b);}
int F(int n){
	if(n==0) return 0;
	if(cache.find(n)!=cache.end()) return cache[n];
	int c=1,j=2;
	int k1=n/j,j2;
	while(k1>1){
		j2=n/k1+1;
		c=add(c,1ll*(j2-j)*F(k1)%P);
		j=j2,k1=n/j2;
	}
	return cache[n]=add(1ll*n*(1ll*n*n%P-1)%P,add(P-c,j));
}
int main(){
	int n;cin>>n;
	int res=F(n);
	cout<<(res%P+P)%P;
}
/*FOOTNOTE OEIS 神秘做法 */

虽然已经和杜教筛大相径庭,但是复杂度分析是一样的。复杂度为 \(\mathcal O(n^{\frac{3}4})\),似乎无法使用预处理方式优化,理论能过,实际上有点卡常。本题所涉及数列是 OEIS A071778,本做法来源于 OEIS 讨论区,作者是来自加州大学伯克利分校的 Chai Wah Wu。

posted @ 2025-06-16 19:43  haozexu  阅读(18)  评论(0)    收藏  举报