原题链接:https://www.luogu.org/problemnew/show/P2257
神犇YY虐完数论后给傻×kAc出了一题
给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对
kAc这种傻×必然不会了,于是向你来请教……
多组输入
第一行一个整数T 表述数据组数
接下来T行,每行两个正整数,表示N, M
T行,每行一个整数表示第i组数据的结果
2
10 10
100 100
30
2791
T = 10000
N, M <= 10000000
日常推式子。。。
设 p p 为素数, P P 表示素数集合:
日常提出 p p :
日常替换 [gcd(i,j)=1] [ g c d ( i , j ) = 1 ] :
日常枚举 d d :
日常枚举 d d 的倍数:
设 T=dp T = d p ,代入:
改为枚举 T T :
设 f(T)=∑p|Tμ(Tp),T=i×p[j] f ( T ) = ∑ p | T μ ( T p ) , T = i × p [ j ] ,考虑线筛:
1.当 T T 本身为素数时,显然有 f(T)=μ(1)=1 f ( T ) = μ ( 1 ) = 1 ;
2.当 T T 拥有多个最小质因子(即 i mod p[j]=0 i m o d p [ j ] = 0 )时:
(1)当 i i 本身无多个相同质因子时,那么当且仅当我们枚举的素数等于 p[j] p [ j ] 时, μ(Tp) μ ( T p ) 的值不为 0 0 ,此时 p=p[j],T=i×p[j] p = p [ j ] , T = i × p [ j ] ,所以有 μ(Tp)=μ(i) μ ( T p ) = μ ( i ) ;
(2)当 i i 本身就是拥有多个因子的数时,无论我们怎么枚举, μ(Tp) μ ( T p ) 的值都为 0 0 ,此时,仍然有 μ(Tp)=μ(i) μ ( T p ) = μ ( i ) ;
3.当 T T 的最小质因子只有一个时:
此时, T T 就比 i i 多了一个质因数 p[j] p [ j ] ,因为有:
因为 i i 中没有质因数 p[j] p [ j ] ,所以有 μ(i×p[j]p)=−μ(ip) μ ( i × p [ j ] p ) = − μ ( i p ) ,在此基础上, T T 还多了一个 μ(i×p[j]p[j])=μ(i) μ ( i × p [ j ] p [ j ] ) = μ ( i ) 。可得, f(T)=−f(i)+μ(i) f ( T ) = − f ( i ) + μ ( i ) ;
综上,我们得到线筛方程:
再求一下 f(T) f ( T ) 的前缀和,利用下底分块,我们就可以 O(n−−√) O ( n ) 解决询问了。
#include
#define R register int
using namespace std;
const int M=1e7+5,N=1e7;
int p[M],miu[M],f[M],T;
bool check[M];
void get()
{
R i,j,t;
check[1]=miu[1]=1;
for(i=2;i<=N;++i)
{
if(!check[i])f[i]=1,miu[i]=-1,p[++p[0]]=i;
for(j=1;j<=p[0];++j)
{
t=i*p[j];if(t>N)break;
check[t]=1;
if(i%p[j]==0){f[t]=miu[i];miu[t]=0;break;}
miu[t]=-miu[i],f[t]=miu[i]-f[i];
}
f[i]+=f[i-1];
}
}
long long ans;
void query(int n,int m)
{
R l,r;ans=0;
if(n>m)swap(n,m);
for(l=1;l<=n;l=r+1)r=min(n/(n/l),m/(m/l)),ans+=1ll*(f[r]-f[l-1])*(n/l)*(m/l);
}
void in(){get();scanf("%d",&T);}
void ac()
{
R i,a,b;
for(i=1;i<=T;++i)
scanf("%d%d",&a,&b),query(a,b),printf("%lld\n",ans);
}
int main()
{
in();ac();
return 0;
}