莫比乌斯反演+分块BZOJ1101-[POI2007]Zap

Posted Yiyi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了莫比乌斯反演+分块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 }

 

以上是关于莫比乌斯反演+分块BZOJ1101-[POI2007]Zap的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 1101 [POI2007]Zap 莫比乌斯反演

BZOJ 1101 [POI2007]Zap(莫比乌斯反演)

bzoj 1101 [POI2007]Zap - 莫比乌斯反演

bzoj 1101 Zap —— 莫比乌斯反演

bzoj 1101 莫比乌斯反演

[bzoj] 1101 Zap || 莫比乌斯反演