传送门
我是菜鸡不会写,我抄题解,我无耻发博客
我看的博客
虽然以上全都属实,但是这个题我确实也学到了些操作
首先先转化一下题意
对于(a,b)要求(a+b|ab),则(gcd(a,b)!=1)
我们考虑将(d=gcd(a,b)),则(a=id,b=jd)
我们知道(gcd(i,j)==1),所以(i+j|ijd)
因为我们知道(gcd(i,j)==1),所以(gcd(i+j,ij)==1)
那么我们要求的就要满足(i+j|d,id<=n,jd<=n,gcd(i,j)==1)
此时答案应该是
[ans=sum_{i=1}^{n}sum_{j=1}^{i-1}lfloor frac{lfloorfrac{n}{i}
floor}{i+j}
floor[gcd(i,j)==1]\
]
考虑(i(i+j)<=n)
[ans=sum_{i=1}^{sqrt{n}}sum_{j=1}^{i-1}lfloor frac{n}{i(i+j)}
floor[gcd(i,j)==1]\
]
考虑(mu)函数的性质
[ans=sum_{i=1}^{sqrt{n}}sum_{j=1}^{i-1}lfloor frac{n}{i(i+j)}
floorsum_{k|gcd(i,j)}mu(k)\
]
设(i=xk,j=yk)
[ans=sum_{k=1}^{sqrt{n}}mu(k)sum_{x=1}^{sqrt{n}/k}sum_{y=1}^{x-1}lfloor frac{n}{xk^2(x+y)}
floor\
]
后面的考虑数论分块,枚举(k,x)后(frac{n}{xk^2})的值就确定了,考虑对于((x+y))的值数论分块
据说总复杂度是(O(n^{frac{4}{3}})),表示不会证
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
void read(int &x) {
char ch; bool ok;
for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
}
#define rg register
const int maxn=1e6+10;long long ans;
int n,m,mu[maxn],pri[maxn],tot;bool vis[maxn];
void prepare(int n)
{
mu[1]=1;
for(rg int i=2;i<=n;i++)
{
if(!vis[i])pri[++tot]=i,mu[i]=-1;
for(rg int j=1;j<=tot&&pri[j]*i<=n;j++)
{
vis[pri[j]*i]=1;
if(!(i%pri[j]))break;
else mu[i*pri[j]]=-mu[i];
}
}
}
long long solve(int k)
{
long long ans=0;
for(rg int x=1;x<=m/k;x++)
{
int g=n/(x*k*k),now=x<<1;if(!g)break;
for(rg int i=x+1,j;i<now;i=j+1)
{
if(!(g/i))break;
j=min(g/(g/i),now-1);
ans=(ans+1ll*(g/i)*(j-i+1));
}
}
return ans;
}
int main()
{
read(n),m=sqrt(n),prepare(m);
for(rg int k=1;k<=m;k++)ans+=mu[k]*solve(k);
printf("%lld
",ans);
}