bzoj2671:Calc

传送门

我是菜鸡不会写,我抄题解,我无耻发博客

我看的博客

虽然以上全都属实,但是这个题我确实也学到了些操作

首先先转化一下题意

对于\(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{\lfloor\frac{n}{i}\rfloor}{i+j}\rfloor[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)}\rfloor[gcd(i,j)==1]\\ \]

考虑\(\mu\)函数的性质

\[ans=\sum_{i=1}^{\sqrt{n}}\sum_{j=1}^{i-1}\lfloor \frac{n}{i(i+j)}\rfloor\sum_{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)}\rfloor\\ \]

后面的考虑数论分块,枚举\(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\n",ans);
}
posted @ 2019-03-19 20:55  蒟蒻--lichenxi  阅读(222)  评论(3编辑  收藏  举报