数论 莫比乌斯反演

前置需求

数论分块

概念

对于一个形如 \(\sum_{x=1}^n \lfloor{\frac{n}{x}}\rfloor\) 的式子,我们发现对于一部分的 \(x\),它们的 \(\lfloor{\frac{n}{x}}\rfloor\) 值相同,因此我们没必要 \(\mathcal{O(n)}\) 计算,可以采用数论分块的办法将这一步的复杂度降低至 \(\mathcal{O(\sqrt{n})}\)。

对于一个已知值 \(n\),给定一个值 \(l\),求一个变量 \(r\) 的最大值使得:\(\lfloor{\frac{n}{l}}\rfloor=\lfloor{\frac{n}{r}}\rfloor\)。比较好得出结论,\(r=\lfloor{\frac{n}{\lfloor{\frac{n}{l}}\rfloor}}\rfloor\)。

证明

摘自 OI-wiki。

应用

在莫反中通常除 \(n\) 外还有一个 \(m\) 形成双层循环,对于它我们只需更改 \(r\) 的位置使得在 \(i\in \left[l,r\right]\) 中 \(\lfloor{\frac{n}{i}}\rfloor\) 与 \(\lfloor{\frac{m}{i}}\rfloor\) 的值始终不变即可。规定 \(n\le m\)。

cpp 复制代码
if(n>m) swap(n,m);
int res=0;
for(int l=1,r;l<=n;l=r+1)
{
	r=min(n/(n/l),m/(m/l));
	res=/*code*/;
}

线性筛

莫反中必用到的知识点之一。

首先了解莫比乌斯函数:

\[\mu(x)=\begin{cases} 1\qquad\quad n=1\\ 0 \qquad\quad n\,含有平方因子\\ (-1)^k\quad k\,为\, n\,本质不同的质因子个数\end{cases}\]

你需要知道的,一是它是一个积性函数,二是怎么线性筛出它。

从定义能看出,\(\mu\) 函数的值跟质数有关,所以在筛它的同时我们还需要线性筛出质数。
最简单的筛

\(u\) 为 \(\mu\) 函数的值,\(N\) 为值域上界,其他的都是筛素数常见的。

cpp 复制代码
int u[N],pri[N],tot;
bool vis[N];
void Wprepare()
{
	u[1]=1;
	for(int i=2;i<=N;i++)
	{
		if(!vis[i]) pri[++tot]=i,u[i]=-1;
		for(int j=1;j<=tot;j++)
		{
			if(i*pri[j]>N) break;
			vis[i*pri[j]]=1;
			if(i%pri[j]==0) break;
			u[i*pri[j]]=-u[i];
		}
	}
}

莫反通常多测,大多数我们需要在准备工作中多预处理一些式子里的其他函数值,有时候还要对其做求前缀和等一系列操作,这些都是因题而异,需要我们灵活应对。

一定的推式子能力

几个显然的很常用的式子转化:

默认 \(n\le m\)

基础一点的:

\[交换律\sum_x\sum\sum f(x)=\sum_x f(x)\sum\sum \]

\[同乘同除,变换上界\sum_{i=1}^n\sum_{j=1}^m [gcd(i,j)=d]=\sum_{i=1}^{\lfloor{\frac{n}{d}}\rfloor}\sum_{j=1}^{\lfloor{\frac{m}{d}}\rfloor}[gcd(i,j)=1] \]

\[等价描述,令\,T=dx:\sum_{d=1}^n\sum_{x=1}^{\lfloor{\frac{n}{d}}\rfloor}=\sum_{T=1}^n \sum_{x|T} \]

提高一点的:

\[综合上面\sum_{i=1}^n \sum_{j=1}^m f(gcd(i,j))=\sum_{d=1}^n f(d)\sum_{i=1}^{\lfloor{\frac{n}{d}}\rfloor} \sum_{j=1}^{\lfloor{\frac{m}{d}}\rfloor} \;[gcd(i,j)=1] \]

\[枚举因数,去循环\sum_{i=1}^n\sum_{j=1}^m\sum_{x|gcd(i,j)} \mu(x)=\sum_{x=1}^n \mu(x)\lfloor{\frac{n}{x}}\rfloor\lfloor{\frac{m}{x}}\rfloor \]

  • 枚举分母,方便数论分块

    令 \(T=dx\)

\[\begin{aligned} Ans &= \sum_{d=1}^n f(d) \sum_{x=1}^{\lfloor{\frac{n}{d}}\rfloor} \mu(x) \lfloor{\frac{n}{dx}}\rfloor \lfloor{\frac{m}{dx}}\rfloor \\ &= \sum_{T=1}^n \lfloor{\frac{n}{T}}\rfloor \lfloor{\frac{m}{T}}\rfloor \sum_{d|T} f(d) \mu(\frac{T}{d}) \end{aligned} \]

主体

由于蒟蒻不会卷积和其他的东西,所以只用到了最基础的一个反演公式

反演公式:

\[[gcd(i,j)=1]=\sum_{d|gcd(i,j)} \mu(d) \]

这是根据莫比乌斯函数的一个性质推出来的:

\[\sum_{d|n}=\begin{cases}1\quad n=1 \\ 0 \quad n\neq 1\end{cases} \]

该性质证明如下:

摘自 OI-wiki。

如果你和我一样对这类式子没有什么太强烈的求知欲,那么食用方法如下:

  • 根据题意,推出式子;
  • 尽可能向 \([gcd(i,j)=1]\) 的方向推,然后使用反演公式;
  • 结合上面的式子转化,推出一个可以预处理出函数值,并能运用数论分块优化复杂度的式子,然后 AC 开始调代码。

例题

做莫反的题我认为关键就在刷题,在不断地推式子中寻找共性,熟能生巧。

先推荐一篇学案,上面的推式子技巧都是循序渐进的,比较好。个人推荐一种学习方式:前几道较基础的题可以看着题解的式子一点一点理解,然后回过头来尝试自己独立完成推式子,再到不断优化筛法。

前几题式子部分会写的详细一点,可能导致篇幅冗长请见谅 qwq。

注:以下题未说明均默认 \(n\le m\)。

YY 的 GCD

这道题虽然在第一题的位置,但要考虑的其实还挺多的,综合了上面几乎所有的推式子技巧。

\[\begin{aligned} Ans&= \sum_{i=1}^n\sum_{j=1}^m \;[gcd(i,j)\in prime] \\ &= \sum_{d=1}^n\sum_{i=1}^n\sum_{j=1}^m \;[gcd(i,j)=d]\;(d\in prime)\\ &= \sum_{d=1}^n\sum_{i=1}^{\lfloor{\frac{n}{d}}\rfloor}\sum_{j=1}^{\lfloor{\frac{m}{d}}\rfloor} \;[gcd(i,j)=1]\;(d\in prime)\\ &=\sum_{d=1}^n\sum_{i=1}^{\lfloor{\frac{n}{d}}\rfloor}\sum_{j=1}^{\lfloor{\frac{m}{d}}\rfloor}\sum_{x|gcd(i,j)}\mu(x)\;(d\in prime)\\&= \sum_{d=1}^n\sum_{x=1}^{\lfloor{\frac{n}{d}}\rfloor}\;\mu(x) \lfloor{\frac{n}{dx}}\rfloor\lfloor{\frac{m}{dx}}\rfloor \;(d\in prime) \end{aligned} \]

令 \(T=dx\),则有:

\[\begin{aligned}Ans&= \sum_{T=1}^n\sum_{d|T} \;\mu(\frac{T}{d})\lfloor{\frac{n}{T}}\rfloor\lfloor{\frac{m}{T}}\rfloor (d\in prime)\\&= \sum_{T=1}^n\;\lfloor{\frac{n}{T}}\rfloor\lfloor{\frac{m}{T}}\rfloor \sum_{d|T} \;\mu(\frac{T}{d})(d\in prime) \end{aligned} \]

发现 \(g(T)= \sum_{d|T} \mu(\frac{T}{d})\) 是可以通过枚举质数的倍数提前处理出来的,对它求前缀和,然后数论分块即可。
点击查看代码

#include<bits/stdc++.h>
using namespace std;
const int Ratio=0;
const int N=1e7+5,M=1e7;
int u[N],pri[N],tot,yz[N],g[N];
void Wpre()
{
    u[1]=1;
    for(int i=2;i<=M;i++)
    {
        if(!yz[i]) pri[++tot]=i,u[i]=-1;
        for(int j=1;j<=tot;j++)
        {
            if(i*pri[j]>M) break;
            yz[i*pri[j]]=1;
            if(i%pri[j]==0) break;
            u[i*pri[j]]=-u[i];
        }
    }
    for(int i=1;i<=tot;i++) for(int j=1;j<=M;j++)
    {
        if(pri[i]*j>M) break;
        g[pri[i]*j]+=u[j];
    }
    for(int i=2;i<=M;i++) g[i]+=g[i-1];
}
int main()
{
    Wpre();
    int T,n,m;scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        if(n>m) swap(n,m);
        long long res=0;
        for(int l=1,r;l<=n;l=r+1)
            r=min(n/(n/l),m/(m/l)),res+=1ll*(g[r]-g[l-1])*(n/l)*(m/l);
        printf("%lld\n",res);
    }
    return Ratio;
}

约数个数和

个人感觉较简单的一道,要点在于求证 \(d(i,j)=\sum_{x|i}\sum_{y|j}[gcd(x,y)=1]\)
简证

摘自洛谷 Siyuan 的题解。

\[\begin{aligned}Ans&= \sum_{i=1}^n\sum_{j=1}^m\;d(ij)\\&= \sum_{i=1}^n\sum_{j=1}^m\sum_{x|i}\sum_{y|j}\;[gcd(x,y)=1]\\&=\sum_{i=1}^n\sum_{j=1}^m\sum_{x|i}\sum_{y|j}\sum_{d|gcd(x,y)}\mu(d)\\&=\sum_{i=1}^n\sum_{j=1}^m\;\lfloor{\frac{n}{i}}\rfloor\lfloor{\frac{m}{j}}\rfloor\sum_{d|gcd(i,j)}\mu(d)\\&=\sum_{d=1}^n\sum_{i=1}^{\lfloor{\frac{n}{d}}\rfloor}\sum_{j=1}^{\lfloor{\frac{m}{d}}\rfloor}\lfloor{\frac{n}{id}}\rfloor\lfloor{\frac{m}{jd}}\rfloor\mu(d)\\&=\sum_{d=1}^n\;\mu(d)\sum_{i=1}^{\lfloor{\frac{n}{d}}\rfloor}\sum_{j=1}^{\lfloor{\frac{m}{d}}\rfloor} \lfloor{\frac{n}{id}}\rfloor\lfloor{\frac{m}{jd}}\rfloor\\&=\sum_{d=1}^n\;\mu(d)\,(\sum_{i=1}^{\lfloor{\frac{n}{d}}\rfloor}\,\lfloor{\frac{n}{id}}\rfloor)\,(\sum_{j=1}^{\lfloor{\frac{m}{d}}\rfloor}\,\lfloor{\frac{m}{jd}}\rfloor) \end{aligned} \]

后面两坨看着就很熟悉是不是,没错就是数论分块的模板。这道题范围是 \(n\le 5\times10^5\),比较小,所以直接对 \(\mu(d)\) 取前缀和,并 \(\mathcal{O(n\sqrt{n})}\) 预处理出后面 \(g(n)=\sum_{i=1}^n \lfloor{\frac{n}{i}}\rfloor\) 值,再运用数论分块即可,查询复杂度 \(\mathcal{O(T\sqrt{n})}\)。
点击查看代码

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int Ratio=0;
const int N=5e4+5,M=5e4;
int u[N],pri[N],tot,yz[N],sum[N];
ll g[N];
void Wpre()
{
    u[1]=1;
    for(int i=2;i<=M;i++)
    {
        if(!yz[i]) pri[++tot]=i,u[i]=-1;
        for(int j=1;j<=tot;j++)
        {
            if(i*pri[j]>M) break;
            yz[i*pri[j]]=1;
            if(i%pri[j]==0) break;
            u[i*pri[j]]=-u[i];
        }
    }
    for(int i=1;i<=M;i++) sum[i]=sum[i-1]+u[i];
    for(int i=1;i<=M;i++)
    {
        ll res=0;
        for(int l=1,r;l<=i;l=r+1)
            r=i/(i/l),res+=1ll*(r-l+1)*(i/l);
        g[i]=res;
    }
}
int main()
{
    Wpre();
    int T,n,m;scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        if(n>m) swap(n,m);
        ll res=0;
        for(int l=1,r;l<=n;l=r+1)
            r=min(n/(n/l),m/(m/l)),res+=(sum[r]-sum[l-1])*g[n/l]*g[m/l];
        printf("%lld\n",res);
    }
    return Ratio;
}

数表

都说是板子题,但我打了 天。

按照能把题做下去的思路,我们先不考虑 \(a\) 的限制,设 \(\sigma (x)\) 为 \(x\) 的因数和,那么显然有:

\[\begin{aligned}Ans&=\sum_{i=1}^n\sum_{j=1}^m\;\sigma(gcd(i,j))\\&= \sum_{d=1}^n\sum_{i=1}^n\sum_{j=1}^m \;[gcd(i,j)=d]\;\sigma(d)\\&=\sum_{d=1}^n\sum_{i=1}^{\lfloor{\frac{n}{d}}\rfloor{}}\sum_{j=1}^{\lfloor{\frac{m}{d}}\rfloor{}}\;[gcd(i,j)=1]\;\sigma(d)\\&=\sum_{d=1}^n\sum_{i=1}^{\lfloor{\frac{n}{d}}\rfloor{}}\sum_{j=1}^{\lfloor{\frac{m}{d}}\rfloor{}}\sum_{x|gcd(i,j)}\mu(x)\,\sigma(d)\\&= \sum_{d=1}^n\;\sigma(d)\sum_{x=1}^{\lfloor{\frac{n}{d}}\rfloor{}}\;\mu(x)\lfloor{\frac{n}{dx}}\rfloor{}\lfloor{\frac{m}{dx}}\rfloor{} \end{aligned} \]

令 \(T=dx\),则有:

\[\begin{aligned}Ans&= \sum_{T=1}^n \sum_{d|T} \;\sigma(d)\,\mu(\frac{T}{d})\,\lfloor{\frac{n}{T}}\rfloor{}\lfloor{\frac{m}{T}}\rfloor{}\\&=\sum_{T=1}^n\;\lfloor{\frac{n}{T}}\rfloor{}\lfloor{\frac{m}{T}}\rfloor{}\sum_{d|T}\;\sigma(d)\,\mu(\frac{T}{d}) \end{aligned} \]

不会求 \(\sigma\) 函数的看这里。

化到这一步,后面的部分已经可以提前处理了,此时考虑加入 \(a\) 的限制条件。

令 $g(T)=\sum_{d|T} \sigma(d),\mu(\frac{T}{d}) $,当 \(\sigma(d)\le a\) 时会对 \(g(T)\) 产生贡献,而对于所有的多测,改变的只是矩形的规格,并不是数值。。。

那么我们完全可以离线下来做!讲所有询问按 \(a\) 升序排序,每当 \(a\) 的值变大时,对有变动的地方插入相应的值。恰好我们所需的是前缀和且带修,所以考虑用树状数组去维护 \(g(T)\) 函数的前缀和。

插入值的复杂度近似于调和级数,树状数组更新复杂度为 \(\mathcal{O(\log n)}\),故修改总复杂度为 \(\mathcal{O(n\log^2 n)}\);采用数论分块优化查询 \(\mathcal{O(\sqrt{n})}\),树状数组查询 \(\mathcal{O(\log n)}\),故查询总复杂度为 \(\mathcal{O(q\sqrt{n}\log n)}\)。程序总复杂度 \(\mathcal{O(n\log^2 n+q\sqrt{n}\log n)}\)。
点击查看代码

cpp 复制代码
#include<bits/stdc++.h>
#define _(a,b) make_pair(a,b)
#define fi first
#define se second
typedef long long ll;
using namespace std;
const int Ratio=0;
const int N=1e5+5,M=1e5;
int u[N],pri[N],tot,yz[N],low[N];
int ans[N],v[N];
pair<int,int> o[N];
struct rmm{int n,m,a,id;}q[N];
bool cmp(rmm A,rmm B){return A.a<B.a;}
void Wpre()
{
    u[1]=1,o[1]=_(1,1);
    for(int i(2);i<=M;i++)
    {
        if(!yz[i]) pri[++tot]=i,u[i]=-1,low[i]=i+1,o[i]=_(i+1,i);
        for(int j(1);j<=tot;j++)
        {
            if(i*pri[j]>M) break;
            yz[i*pri[j]]=1;
            if(i%pri[j]==0)
            {
                low[i*pri[j]]=low[i]*pri[j]+1;
                o[i*pri[j]]=_(o[i].fi/low[i]*low[i*pri[j]],i*pri[j]);
                break;
            }
            u[i*pri[j]]=-u[i];
            low[i*pri[j]]=pri[j]+1;
            o[i*pri[j]]=_(o[i].fi*o[pri[j]].fi,i*pri[j]);
        }
    }
    sort(o+1,o+M+1);
}
void Wupd(int x,int k){for(;x<=M;x+=(x&-x)) v[x]+=k;}
int Wq(int x)
{
    int res=0;
    while(x) res+=v[x],x-=(x&-x);
    return res;
}
int main()
{
    Wpre();
    int T;scanf("%d",&T);
    for(int i(1);i<=T;i++) scanf("%d%d%d",&q[i].n,&q[i].m,&q[i].a),q[i].id=i;
    sort(q+1,q+1+T,cmp);
    int j=1;
    for(int i(1);i<=T;i++)
    {
        while(j<=M&&o[j].fi<=q[i].a)
        {
            for(int k(o[j].se);k<=M;k+=o[j].se)
                Wupd(k,o[j].fi*u[k/o[j].se]);
            j++;
        }
        int res=0,n=q[i].n,m=q[i].m;
        if(n>m) swap(n,m);
        for(int l(1),r;l<=n;l=r+1)
            r=min(n/(n/l),m/(m/l)),res+=(Wq(r)-Wq(l-1))*(n/l)*(m/l);
        ans[q[i].id]=res;
    }
    for(int i(1);i<=T;i++) printf("%d\n",(ans[i]&(~(1<<31))));
    return Ratio;
}

DZY Loves Math

有新函数,先不管它,推式子。

\[\begin{aligned}Ans&=\sum_{i=1}^n\sum_{j=1}^m \;f(gcd(i,j))\\ &=\sum_{d=1}^n\sum_{i=1}^n\sum_{j=1}^m\;[gcd(i,j)=d] \,f(d)\\&=\sum_{d=1}^n\sum_{i=1}^{\lfloor{\frac{n}{d}}\rfloor{}}\sum_{j=1}^{\lfloor{\frac{m}{d}}\rfloor{}}\;[gcd(i,j)=1]\,f(d)\\&=\sum_{d=1}^n\;f(d)\sum_{i=1}^{\lfloor{\frac{n}{d}}\rfloor{}}\sum_{j=1}^{\lfloor{\frac{m}{d}}\rfloor{}}\sum_{x|gcd(i,j)}\mu(x)\\&=\sum_{d=1}^n\;f(d)\sum_{x=1}^{\lfloor{\frac{n}{d}}\rfloor{}}\;\mu(x)\lfloor{\frac{n}{dx}}\rfloor{}\lfloor{\frac{m}{dx}}\rfloor{} \end{aligned} \]

令 \(T=dx\),则有:

\[\begin{aligned}Ans&=\sum_{T=1}^n\;\lfloor{\frac{n}{T}}\rfloor{}\lfloor{\frac{m}{T}}\rfloor{}\sum_{d|T}\;f(d)\,\mu(\frac{T}{d}) \end{aligned} \]

到这一步似乎就可以做了,不过后面的那坨 $g(T)=\sum_{d|T}\ f(d)\ \mu(\frac{T}{d}) $ 需要调和级数预处理,\(n\le 10^7\),在一个月前的题库上是能跑过的,不过现在不知道为什么速度慢了一半,所以需要我们继续优化,用线性复杂度处理出。

我们着眼于 \(g(T)\) 这个函数。设 \(T\) 共有 \(k\) 个不同的质因子,将其分解为 $T=\prod_{i=1}^k\ p_i^{a_i} $ 。令 \(T\) 的一个因子 \(d\) 分解为 \(d=\prod_{i=1}^k \;p_i^{b_i}\),发现 \(d\) 有贡献当且仅当 \(\mu(\frac{T}{d})\neq 0\),即 \(\forall i\in[1,k], \;a_i-b_i\le 1\),换句话说 \(b_i\) 的取值只能是 \(a_i\) 或 \(a_i-1\)。

然后再分两种情况:

一种是 \(a_i\) 不全相等的情况,此时必有 $存在 \ i,j\in\ [1,k],a_i\lt a_j $,考虑 \(b_i\) 无论取 \(a_i\) 或 \(a_i-1\),不会对 \(f(T)\) 的值产生影响,且两种取法的 \(\mu\) 值之和为 \(0\),即:此时无论如何分配 \(b_i\) 的值,最终结果总能两两分配出相加为 \(0\) 的情况,故 \(g(T)=0\)

另外就是 \(a_i\) 全部相等的情况。此时有贡献的 \(d\) 共有 \(2^k\) 种取值,已知 \(\binom{0}{k}+\binom{2}{k}+\cdots+\binom{2\times \lfloor{\frac{k}{2}}\rfloor{}}{k}=\binom{1}{k}+\binom{3}{k}+\cdots+\binom{2\times \lfloor{\frac{k-1}{2}}\rfloor{}+1}{k}\),即杨辉三角中每行的奇数项和等于偶数项和。括号中上面的数恰好可对应 \(a_i-b_i\) 中值为 \(1\) 的数量,即在 \(f(d)\) 均相同的情况下,\(g(T)\) 的值是 \(0\)。但当括号中上面的数等于 \(k\),即 \(\forall \;i\in[1,k],b_i=a_i-1\) 时,\(f(d)=a_i-1\)。

稍微理解下,然后再来分情况。若 \(k\) 为奇数,则当 \(\forall\;i\in[1,k],b_i=a_i-1\) 时,\(\mu(\frac{T}{d})=(-1)^k=-1\),也就是说,在对结果产生贡献的那一步中本应该减去 \(a_i\),但实际上减去了 \(a_i-1\),那么最终 \(g(T)=1\);若 \(k\) 为偶数同理,此时 \(\mu(\frac{T}{d})=1\),那么本应该加上 \(a_i\),但实际上只加了 \(a_i-1\),最终 \(g(T)=-1\)。

整合一下,发现 \(g\) 函数的取值如下:

\[g(T)=\begin{cases}0\quad\quad\quad\quad 存在 \; i,j\in[1,k],a_i\lt a_j\\ (-1)^{k+1}\quad\, \forall\;i,j\in[1,k],a_i=a_j \end{cases} \]

其中 \(k\) 为 \(T\) 的质因子个数。

实现中,记录最小质因子的指数和它的指数次幂,转移时判断除去最小质因子后次小质因子的指数是否与之相同即可。

预处理 \(g\) 函数及前缀和的复杂度为 \(\mathcal{O(n)}\),数论分块优化后查询复杂度为 \(\mathcal{O(T\sqrt{n})}\),总复杂度 \(\mathcal{O(n+T\sqrt{n})}\)。
点击查看代码

cpp 复制代码
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int Ratio=0;
const int N=1e7+5,M=1e7;
int n,m;
int u[N],pri[N],tot,yz[N],Index[N],low[N],g[N];
void Wpre()
{
    u[1]=1,g[1]=0;
    for(int i(2);i<=M;i++)
    {
        if(!yz[i]) low[i]=pri[++tot]=i,u[i]=-1,Index[i]=g[i]=1;
        for(int j(1);j<=tot;j++)
        {
            if(i*pri[j]>M) break;
            yz[i*pri[j]]=1;
            if(i%pri[j]==0)
            {
                Index[i*pri[j]]=Index[i]+1;
                low[i*pri[j]]=low[i]*pri[j];
                if(low[i]==i) g[i*pri[j]]=1;
                else g[i*pri[j]]=Index[i/low[i]]==Index[i*pri[j]]?-g[i/low[i]]:0;
                break;
            }
            u[i*pri[j]]=-u[i];
            Index[i*pri[j]]=1;
            low[i*pri[j]]=pri[j];
            g[i*pri[j]]=Index[i]==1?-g[i]:0;
        }
    }
    for(int i(2);i<=M;i++) g[i]+=g[i-1];
}
int main()
{
    Wpre();
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        if(n>m) swap(n,m);
        ll res=0;
        for(int l(1),r;l<=n;l=r+1)
            r=min(n/(n/l),m/(m/l)),res+=1ll*(g[r]-g[l-1])*(n/l)*(m/l);
        printf("%lld\n",res);
    }
    return Ratio;
}

其他例题会逐渐更新。

制作不易,如有帮助,请推荐支持,感谢!

相关推荐
紫郢剑侠4 天前
Linux shell编程学习笔记80:gzip命令——让文件瘦身
linux·学习笔记·shell编程·脚本编程
紫郢剑侠5 天前
Linux shell编程学习笔记78:cpio命令——文件和目录归档工具(上)
linux·学习笔记·shell编程·脚本编程·cpio
吃土少女古拉拉9 天前
CSRF,SSRF和重放攻击的区别
安全·学习笔记
_yuen10 天前
tarjan—算法的神(一)
学习笔记·图论·tarjan
StaDark18 天前
c#学习笔记(一)
c#·学习笔记
搞机械的假程序猿18 天前
C++学习笔记——反序输出
c++·学习笔记
腾飞开源1 个月前
02_TensorFlow2 Eager Execution:让AI编程从‘慢条斯理’变‘急不可耐’的神奇魔法!
人工智能·深度学习·系统架构·aigc·tensorflow·学习笔记·ai编程
DrRatio1 个月前
离线算法 莫队算法进阶
学习笔记
紫郢剑侠1 个月前
Linux shell编程学习笔记72:tr命令——集合转换工具
linux·学习笔记·shell编程·脚本编程·tr命令·md5sum命令