Math is Simple-2020杭电多校1
题意:
计算:
\[\sum_{1\leq a<b \leq n \\ gcd(a,b)=1 \\ a+b \geq n}{\frac{1}{ab}}
\]
其中,\(2\leq n \leq 10^8\)。
分析:
令
\[f(n)=\sum_{1\leq a<b \leq n \\ gcd(a,b)=1 \\ a+b \geq n}{\frac{1}{ab}}
\]
考虑递推,有:
\[f(n)=f(n-1)+\sum_{1\leq a<b \leq n \\ gcd(a,b)=1 \\ a+b=n}{\frac{1}{ab}}-\sum_{1\leq a<b \leq n-1 \\ gcd(a,b)=1 \\ a+b=n-1}{\frac{1}{ab}}
\]
可以发现,后面两项的差别仅在于 \(n\) 和 \(n-1\),可令:
\[g(n)=\sum_{1\leq a<b \leq n \\ gcd(a,b)=1 \\ a+b=n}{\frac{1}{ab}}
\]
有:
\[\begin{align}
f(n)&=f(n-1)+g(n)-g(n-1)\\
& = (f(n-2)+g(n-1)-g(n-2))+g(n)-g(n-1)\\
& =\ ...\\
& = f(2)-g(2)+g(n)
\end{align}
\]
其中可以手算出:\(f(2)=\frac{1}{2},g(2)=0\)
最终可得:
\[f(n)=\frac{1}{2}+g(n)
\]
接下来计算 \(g(n)\):
\[g(n)=\sum_{1\leq a<b \leq n \\ gcd(a,b)=1 \\ a+b=n}{\frac{1}{ab}}
\]
其中,
\[\begin{align}
\frac{1}{ab} & = \frac{1}{a(n-a)}\\
& = \frac{1}{n}(\frac{1}{a}+\frac{1}{n-a})
\end{align}
\]
又根据更相减损法:
\[gcd(a,n)=gcd(a,n-a)
\]
所以:
\[\begin{align}
g(n) & = \frac{1}{n} \sum_{1\leq a< n-a \leq n \\ gcd(a,n-a)=1}{\frac{1}{a}+\frac{1}{n-a}}\\
& = \frac{1}{n} \sum_{1\leq a\leq n \\ gcd(a,n)=1}{\frac{1}{a}}
\end{align}
\]
继续推导:
\[\begin{align}
g(n) &= \frac{1}{n} \sum_{1\leq a\leq n \\ gcd(a,n)=1}{\frac{1}{a}}\\
& = \frac{1}{n} \sum_{a=1}^{n}{\frac{1}{a}[gcd(a,n)=1]}\\
& = \frac{1}{n} \sum_{a=1}^{n}{\frac{1}{a} \sum_{d|gcd(a,n)}{\mu(d)}}\\
& = \frac{1}{n} \sum_{d|n}^{n}{\mu(d)\sum_{i=1}^{\frac{n}{d}}{\frac{1}{id}}}\\
& = \frac{1}{n} \sum_{d|n}^{n}{\mu(d) \frac{1}{d} \sum_{i=1}^{\frac{n}{d}}{\frac{1}{i}}}
\end{align}
\]
以上推导中运用了莫比乌斯函数的性质:
\[ \sum_{d|n}{\mu(d)}=\begin{cases} 1,&\ n=1 \\ 0,& \ n>1 \end{cases}
\]
其中,\(S(m)=\sum_{i=1}^{m}{\frac{1}{i}}\),可以利用递推逆元 \(O(n)\) 求出。
最终的结果为:
\[g(n)=\frac{1}{n} \sum_{d|n}^{n}{\mu(d) \frac{1}{d} S(\frac{n}{d})}
\]
递推逆元:
\[inv[i]=(-(mod/i)*inv[mod\%i]\%mod+mod)\%mod
\]
但由于内存的限制,\(S\) 数组只能开 \(int\) 型,并且无法预处理出莫比乌斯函数的值,只能临时求。
先预处理出 \(n\) 所有素因子,用一个大小为 \(100\) 左右的数组保存,用来求 \(n\) 的各个因子的莫比乌斯函数值。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353;
const int N=1e8+5;
const int maxn=1e2+5;
int S[N];
int factor[maxn],cnt,inv2=499122177;
void init()//预处理逆元和
{
int len=1e8;
S[1]=1;
for(int i=2;i<=len;i++)//递推求逆元
S[i]=(-1LL*(mod/i)*S[mod%i]%mod+mod)%mod;
for(int i=2;i<=len;i++)
S[i]=(S[i-1]+S[i])%mod;
}
void divide(int num)//质因子分解
{
cnt=0;
for(int i=2;i*i<=num;i++)
{
if(num%i==0)
{
factor[++cnt]=i;
while(num%i==0)
num/=i;
}
}
if(num>1)
factor[++cnt]=num;
}
int get_mu(int num)//计算莫比乌斯函数
{
int cot=0;
if(num==1) return 1;
for(int i=1;i<=cnt&&factor[i]<=num;i++)
{
if(num%factor[i]==0)
{
cot++;
num/=factor[i];
if(num%factor[i]==0) return 0;
}
}
return (cot%2==0?1:-1);
}
int main()
{
int t,n;
scanf("%d",&t);
init();
while(t--)
{
scanf("%d",&n);
if(n==2)
{
printf("%d\n",inv2);
continue;
}
divide(n);
ll ans=0;
ll invn=S[n]-S[n-1];
for(int i=1;i*i<=n;i++)
{//逆元可以利用预处理逆元和作差
if(n%i) continue;
int d=n/i;
int mu=get_mu(i);
ans=(ans+1LL*mu*(S[i]-S[i-1])%mod*S[d]%mod)%mod;//S是int
if(i!=d)
{
mu=get_mu(d);
ans=(ans+1LL*mu*(S[d]-S[d-1])%mod*S[i]%mod)%mod;
}
}
ans=(ans*invn%mod+inv2)%mod;
printf("%lld\n",(ans+mod)%mod);//可能是负数
}
return 0;
}