洛谷 P4844 LJJ爱数数
题目链接
显然,我们要找到 \(i\),\(j\),使 \(gcd(i,j)=1\),构造出的方案为 \((i^2+ij,j^2+ij,ij)\) 和 \((j^2+ij,i^2+ij,ij)\)。
这里我们令 \(i \geq j\),则方案个数为
\(\sum\limits_{i=1}^n{\sum\limits_{j=1}^i{[gcd(i,j)=1][i^2+ij \leq n]}}\)
对于 \(i^2+ij \leq n\),我们求出 \(j \leq \frac{n}{i}-i\),再解 \(\frac{n}{2}-i \geq 0\),得 \(i \leq \sqrt{n}\),把式子改一下:
\(\sum\limits_{i=1}^{\sqrt{n}}{\sum\limits_{j=1}^{\min (\frac{n}{i}-i,i)}{[gcd(i,j)=1]}}\)
好哒,我们再看一看 \(\frac{n}{i}-i=i\),解得 \(i=\sqrt{\frac{n}{2}}\),分情况讨论:
当 \(i \leq \sqrt{\frac{n}{2}}\) 时,就等价于统计 \(\sum\limits_{j=1}^{i}{[gcd(i,j)=1]}\),线性筛 \(\phi\) 即可。
当 \(\sqrt{\frac{n}{2}} < i \leq \sqrt{n}\) 时,\(j \leq i\),这个时候怎么办呢?
我们暴力容斥就好啦,线性筛时顺便筛出每个数的最小质因子,分解,设有 \(K\) 个不同的质因子,则 \(j\) 内与 \(i\) 互质的数有:
\(j-\sum\limits_{k=1}^{K}{(-1)^k*f(k)}\),\(f(k)=\sum\limits_{a_1<a_2< \cdots <a_k \leq K}{\frac{j}{\prod\limits_{i=1}^{k}{p_{a_i}}}}\)
最后把输出 \(2ans-1\),再加上两个剪枝,就可以轻松跑过啦~
\(\frak{code:}\)
#include<bits/stdc++.h>
#define IL inline
#define LL long long
using namespace std;
const int N=1e6+3;
int vis[N],pri[N],mu[N],a[N],now,num;
LL n,m,res,Max,ans,phi[N];
void init(int n){ //线性筛~
phi[1]=mu[1]=1;
for(int i=2;i<=n;++i){
if(!vis[i]) vis[i]=i,pri[++pri[0]]=i,phi[i]=i-1,mu[i]=-1;
for(int j=1,k;(k=i*pri[j])<=n;++j){
vis[k]=pri[j];
if(i%pri[j]) mu[k]=-mu[i],phi[k]=phi[i]*phi[pri[j]];
else{phi[k]=phi[i]*pri[j];break;}
}
}
}
void calc(int n){ //分解质因数~
a[0]=0;
while(n^1){
if(vis[n]^a[a[0]]) a[++a[0]]=vis[n];
n/=vis[n];
}
}
void dfs(int k,int kk,int val,int op){ //搜索组合方案~
if(kk==num){ans+=op*(now/val);return;}
if(a[0]-k+1<num-kk) return; //显而易见的剪枝1~
dfs(k+1,kk+1,val*a[k],op);
dfs(k+1,kk,val,op);
}
int main()
{
scanf("%lld",&n);init(1e6);
m=sqrt(1.0*n/2),Max=sqrt(n);
for(int i=1;i<=m;++i) ans+=phi[i];
for(int i=m+1,k;i<=Max;++i){
now=n/i-i;int res=ans;
calc(i),ans+=now;
for(num=1,k=a[num];num<=a[0];++num,k*=a[num]){
if(k>now) break; //显而易见的剪枝2,如果最小的num个质因子相乘大于now,则之后的贡献都为0~
dfs(1,0,1,num&1?-1:1);
}
}
cout<<ans*2-1<<endl; //(2,2,1)会被算2次,所以减1~
return 0;
}