【莫比乌斯反演+分块】BZOJ1101-[POI2007]Zap
【题目大意】
对于给定的整数a,b和d,有多少正整数对x,y,满足x<=a,y<=b,并且gcd(x,y)=d。
【思路】
前面的思路同HDU1695
不过不同的是这道题中(a,b)和(b,a)算作同一种情况,不需要再减去重复的情况。
这道题运用了分块加快效率。我们可以注意到是相同的,b'(b'/i)b表示和当前商相同的最后一位[b'/d],d'(d'/i)同理,pos为两者中较小的一个。我们预处理Miu的前缀和,就可以将一样的*(sum[pos]-pos[k-1])即可!
??BZOJ一定要用printf%lld,cout会RE??
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 typedef long long ll; 7 const int MAXN=50000+50; 8 const int INF=0x7ffffff; 9 int a,b,d; 10 int miu[MAXN]; 11 int miu_sum[MAXN]; 12 13 void get_miu(int maxn) 14 { 15 int prime[MAXN],pnum=0; 16 memset(miu_sum,0,sizeof(miu_sum)); 17 miu[1]=miu_sum[1]=1; 18 for (int i=2;i<maxn;i++) miu[i]=-INF; 19 for (int i=2;i<maxn;i++) 20 { 21 if (miu[i]==-INF) 22 { 23 miu[i]=-1; 24 prime[++pnum]=i; 25 } 26 for (int j=1;j<=pnum;j++) 27 { 28 if (i*prime[j]>=maxn) break; 29 if (i%prime[j]==0) miu[i*prime[j]]=0; 30 else miu[i*prime[j]]=-miu[i]; 31 } 32 miu_sum[i]=miu_sum[i-1]+miu[i]; 33 } 34 } 35 36 ll get_ans(int a,int b,int d) 37 { 38 int ub=min(a,b),pos; 39 ll ans=0; 40 for (int i=1;i<=ub;i=pos+1) 41 { 42 pos=min(a/(a/i),b/(b/i)); 43 ans+=(ll)(miu_sum[pos]-miu_sum[i-1])*(a/i)*(b/i); 44 } 45 return ans; 46 } 47 48 int main() 49 { 50 int T; 51 scanf("%d",&T); 52 get_miu(MAXN-1); 53 for (int i=0;i<T;i++) 54 { 55 scanf("%d%d%d",&a,&b,&d); 56 a/=d;b/=d; 57 printf("%lld\n",get_ans(a,b,d)); 58 } 59 }