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;
}


参考博客:
https://www.cnblogs.com/dysyn1314/p/13362488.html

posted @ 2020-08-01 09:35  xzx9  阅读(152)  评论(0编辑  收藏  举报