神犇YY虐完数论后给傻×kAc出了一题
给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对
kAc这种傻×必然不会了,于是向你来请教……
多组输入
标签:
T = 10000
N, M <= 10000000
莫比乌斯反演
与bzoj2301类似,答案ans=∑(p)∑(1≤d≤n/p)mu[d]*(n/pd)*(n/pd)。
令T=pd,则ans=∑(1≤T≤n)(n/T)*(m/T)∑(p|T)mu[T/p]。
设f(T)=∑(p|T)mu[T/p],如果能预处理出f(T)和前缀和,则采用分块就可以在O(sqrt(n))复杂度内完成单次询问。
如何预处理?只需要枚举每一个质数,暴力修改它的所有倍数即可。因为每个质数的修改次数均摊ln(n),而n以内质数个数接近n/ln(n),则总复杂度是约等于O(n)的。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #define F(i,j,n) for(int i=j;i<=n;i++) #define D(i,j,n) for(int i=j;i>=n;i--) #define ll long long #define maxn 10000000 using namespace std; int n,m,t,tot; int pri[maxn+5],mu[maxn+5]; ll f[maxn+5]; bool mark[maxn+5]; inline int read() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline void getmu() { mu[1]=1; F(i,2,maxn) { if (!mark[i]) pri[++tot]=i,mu[i]=-1; for(int j=1;j<=tot&&i*pri[j]<=maxn;j++) { mark[i*pri[j]]=true; if (i%pri[j]==0){mu[i*pri[j]]=0;break;} else mu[i*pri[j]]=-mu[i]; } } F(i,1,tot) for(int j=1;j*pri[i]<=maxn;j++) f[j*pri[i]]+=mu[j]; F(i,1,maxn) f[i]+=f[i-1]; } int main() { getmu(); t=read(); while (t--) { ll ans=0; n=read();m=read(); if (n>m) swap(n,m); for(int i=1,pos;i<=n;i=pos+1) { pos=min(n/(n/i),m/(m/i)); ans+=(f[pos]-f[i-1])*(n/i)*(m/i); } printf("%lld\n",ans); } return 0; }
标签:
原文地址:http://blog.csdn.net/aarongzk/article/details/51059682