Description
对于100%的数据:
1≤n,m≤100,000
Analysis
首先,让我们想一想,线段上会碰到多少个植物其实是什么?
假设坐标为
(dn,dm),d=gcd(n,m),x=nd,y=md
。
那么对于所有的
xi,yi(xi≤n,yi≤m)
都会被直线碰到。
这样的坐标
(x,y)
有
nx=my=d
个,就是
gcd(n,m)
。
当然实际不算
(n,m)
本身,所以实际是
gcd(n,m)−1
个。
所以,我们可以愉快地玩耍了。
Ans=∑i=1n∑j=1m2∗(gcd(i,j)−1)−1
=2∑i=1n∑j=1mgcd(i,j)−n∗m
∑ 前面后面的部分都水,主要是 ∑ 部分,一看,嘿嘿,标准莫比乌斯反演形式。
设 f(d) 表示 gcd(i,j)=d 的个数, g(d) 表示 d|gcd(i,j) 的个数。
我们有
g(d)=∑i=1⌊nd⌋f(d∗i)
反演
f(d)=∑i=1⌊nd⌋g(d∗i)∗μ(i)
易知 g(d∗i)=⌊nd∗i⌋∗⌊md∗i⌋ ,代回原式
f(d)=∑i=1⌊nd⌋⌊nd∗i⌋∗⌊md∗i⌋∗μ(i)
而
Ans=2∑d=1nd∗f(d)−n∗m
=2∑d=1nd∗∑i=1⌊nd⌋⌊nd∗i⌋∗⌊md∗i⌋∗μ(i)−n∗m
其实直接上这个式子就能过了,后面那个分块跑得更快一些,但是我比较无聊打了两个分块,快得飞飞飞飞飞起。
Code
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int N=100010;
ll n,m,pri[N],mu[N];
bool bz[N];
void pre()
{
mu[1]=1;
fo(i,2,n)
{
if(!bz[i]) bz[i]=1,mu[i]=-1,pri[++pri[0]]=i;
fo(j,1,pri[0])
{
ll t=i*pri[j];
if(t>n) break;
bz[t]=1;
if(i%pri[j]==0)
{
mu[t]=0;
break;
}
mu[t]=mu[i]*mu[pri[j]];
}
}
fo(i,1,n) mu[i]+=mu[i-1];
}
int main()
{
scanf("%lld %lld",&n,&m);
if(n>m) swap(n,m);
pre();
ll j,ans=0;
for(ll i=1;i<=n;i=j+1)
{
j=min(n/(n/i),m/(m/i));
ll n1=n/i,m1=m/i,j1,t=0;
for(ll i1=1;i1<=n1;i1=j1+1)
{
j1=min(n1/(n1/i1),m1/(m1/i1));
t+=(n1/i1)*(m1/i1)*(mu[j1]-mu[i1-1]);
}
ans+=(i+j)*(j-i+1)/2*t;
}
printf("%lld",2*ans-n*m);
}