1101: [POI2007]Zap
Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 1646 Solved: 577
Description
FGD正在破解一段密码,他需要回答很多类似的问题:对于给定的整数a,b和d,有多少正整数对x,y,满足x<=a,y<=b,并且gcd(x,y)=d。作为FGD的同学,FGD希望得到你的帮助。
Input
第一行包含一个正整数n,表示一共有n组询问。(1<=n<= 50000)接下来n行,每行表示一个询问,每行三个正整数,分别为a,b,d。(1<=d<=a,b<=50000)
Output
对于每组询问,输出到输出文件zap.out一个正整数,表示满足条件的整数对数。
Sample Input
2
4 5 2
6 4 3
Sample Output
3
2
HINT
对于第一组询问,满足条件的整数对有(2,2),(2,4),(4,2)。对于第二组询问,满足条件的整数对有(6,3),(3,3)。
Source
本题为mobius反演:
PS:计算过程不能用long long 不然TLE
公式推导
这部分让我们看看PoPoQQQ的PPT《莫比乌斯反演》
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<functional> #include<iostream> #include<cmath> using namespace std; #define For(i,n) for(int i=1;i<=n;i++) #define Fork(i,k,n) for(int i=k;i<=n;i++) #define MEM(a) memset(a,0,sizeof(a)); #define MAXN (50000+10) typedef long long ll; int p[MAXN]={0},tot; bool b[MAXN]={0}; int mu[MAXN]={0},sum[MAXN]={0}; 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; } void make_prime(int n) { tot=0; mu[1]=1; Fork(i,2,n) { if (!b[i]) p[++tot]=i,mu[i]=-1; For(j,tot) { if (i*p[j]>n) break; b[i*p[j]]=1; if (i%p[j]==0) { mu[i*p[j]]=0; break; } mu[i*p[j]]=-mu[i]; } } sum[0]=0; For(i,n) sum[i]=sum[i-1]+mu[i]; } int n,m,d; int calc() { int ans=0; for(int i=1,last=1;i<=n;i=last+1) { last=min(n/(n/i),m/(m/i)); ans+=(sum[last]-sum[i-1])*(n/i)*(m/i); } printf("%d\n",ans); return ans; } int main() { // freopen("bzoj1101.in","r",stdin); MEM(p) MEM(b) MEM(mu) MEM(sum) int N = 50000; make_prime(N); int T;T=read(); while(T--) { n=read(); m=read(); d=read(); if (n>m) swap(n,m); n/=d,m/=d; calc(); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-27 19:04:47