神犇YY虐完数论后给傻×kAc出了一题
给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对
kAc这种傻×必然不会了,于是向你来请教……
多组输入
T = 10000
N, M <= 10000000
莫比乌斯函数。
iwtwiioi的题解非常详细orz
大概说一下做法,求gcd(x,y)=k的(x,y)的对数就是【BZOJ 1101】,那么这道题可以枚举k来求,但是会TLE,那么我们考虑公式的变形。(详见iwtwiioi的题解。。)
接下来的关键就是求g[x]函数:根据线性筛的原理,为了方便,把g[x]变成求g[kp]。
k是线性筛的时候当前要处理的数,p是枚举已经筛出来的质数(一定<k)。
就像求莫比乌斯函数一样,分三种情况:
1.k为质数,g[k]=1
2.k%p=0,说明p的指数>=2,然后根据g[x]函数的计算方法来计算此时的g[kp],分p‘=p和p‘!=p两种情况。
得出g[kp]=mu[k]
3.k%p!=0,说明p的指数=1,然后根据g[x]函数的计算方法来计算此时的g[kp],分p‘=p和p‘!=p两种情况。
得出g[kp]=-g[k]
于是在求莫比乌斯函数的同时就把g数组求好了,按照原来的分块方法计算即可~
#include <iostream> #include <cmath> #include <algorithm> #include <cstdio> #include <cstdlib> #include <cstring> #define LL long long #define M 10000005 using namespace std; int check[M],mu[M],p[M],sum[M],g[M]; void Getmobius() { mu[1]=1; int tot=0; for (int i=2;i<=M;i++) { if (!check[i]) { p[++tot]=i; mu[i]=-1; g[i]=1; } for (int j=1;j<=tot;j++) { if (p[j]*i>M) break; check[p[j]*i]=1; if (i%p[j]==0) { mu[p[j]*i]=0; g[p[j]*i]=mu[i]; break; } mu[p[j]*i]=-mu[i]; g[p[j]*i]=mu[i]-g[i]; } } for (int i=1;i<=M;i++) sum[i]=sum[i-1]+g[i]; } LL Calc(int a,int b) { LL ans=0LL; int pos; for (int d=1;d<=min(a,b);d=pos+1) { pos=min(a/(a/d),b/(b/d)); ans+=(LL)(sum[pos]-sum[d-1])*(a/d)*(b/d); } return ans; } int main() { Getmobius(); int T; scanf("%d",&T); while (T--) { int n,m; scanf("%d%d",&n,&m); printf("%lld\n",Calc(n,m)); } return 0; }
感悟:
1.发现普通的计算方法TLE,对式子变形化简
2.求g数组套在线性筛中~
原文地址:http://blog.csdn.net/regina8023/article/details/43877249