Description
给定n,m(n,m<=107), 求 $\sum\limits_{x=1}^{n}\sum\limits_{y=1}^{m}[gcd(x,y)=质数]$。(多组数据,T<=10000)
Solution
这题是一道模板题,用下面这条公式就能解决啦~
$\sum\limits_{d|n}μ(d)=[n=1]$
$ans=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}[gcd(i,j)=质数]$
$=\sum\limits_{p}\sum\limits_{i=1}^{\left\lfloor\frac{n}{p}\right\rfloor}\sum\limits_{j=1}^{\left\lfloor\frac{m}{p}\right\rfloor}[gcd(i,j)=1]$ (p为质数)
$=\sum\limits_{p}\sum\limits_{i=1}^{\left\lfloor\frac{n}{p}\right\rfloor}\sum\limits_{j=1}^{\left\lfloor\frac{m}{p}\right\rfloor}\sum\limits_{d|i,d|j}μ(d)$
$=\sum\limits_{p}\sum\limits_{d=1}^{\left\lfloor\frac{n}{p}\right\rfloor}μ(d)\left\lfloor\frac{n}{pd}\right\rfloor\left\lfloor\frac{m}{pd}\right\rfloor$
记 $c=pd$ ,则
$ans=\sum\limits_{c=1}^{n}\sum\limits_{p|c}μ(\frac{c}{p})\left\lfloor\frac{n}{c}\right\rfloor\left\lfloor\frac{m}{c}\right\rfloor$
最后用线性筛预处理出$μ(d)$的前缀和,然后按照$\left\lfloor\frac{n}{c}\right\rfloor$的值分块处理就可以啦,时间复杂度$O(T\sqrt{n})$。
Code
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=10000000; 6 int t,n,m,p[N+10]={0},miu[N+10]={0,1},g[N+10]={0},f[N+10]={0}; 7 bool check[N+10]={false}; 8 void get_miu(){ 9 for(int i=2;i<=N;i++){ 10 if(!check[i]){ 11 miu[p[++p[0]]=i]=-1; 12 g[i]=1; 13 } 14 for(int j=1;i*p[j]<=N&&j<=p[0];j++){ 15 check[i*p[j]]=true; 16 if(i%p[j]){ 17 miu[i*p[j]]=-miu[i]; 18 g[i*p[j]]=miu[i]-g[i]; 19 } 20 else{ 21 g[i*p[j]]=miu[i]; 22 break; 23 } 24 } 25 } 26 for(int i=1;i<=N;i++) 27 f[i]=f[i-1]+g[i]; 28 return; 29 } 30 int main(){ 31 get_miu(); 32 scanf("%d",&t); 33 while(t--){ 34 scanf("%d%d",&n,&m); 35 if(n>m) 36 swap(n,m); 37 long long ans=0; 38 for(int i=1,j;i<=n;i=j+1) 39 ans+=(long long)(f[j=min(n/(n/i),m/(m/i))]-f[i-1])*(n/i)*(m/i); 40 printf("%lld\n",ans); 41 } 42 return 0; 43 }