BZOJ 2301 [HAOI2011]Problem b (莫比乌斯反演)

题目大意:已知x\in [a,b],y\in [c,d],求gcd(x,y)为k的有序数对数量 a,b,c,d,k及询问数<=50000

yy的gcd好做一些吧

转化题目,直接求解比较困难,利用容斥原理,问题转化为求$ans(b,d)-ans(a-1,d)-ans(b,c-1)+ans(a-1,c-1)$

求$\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)==k]$

化简$\sum_{i=1}^{\left \lfloor \frac{n}{k} \right \rfloor}\sum_{j=1}^{\left \lfloor \frac{m}{k} \right \rfloor}[gcd(i,j)==1]$

套路变形$\sum_{d=1}^{\left \lfloor \frac{n}{k} \right \rfloor}\left \lfloor \frac{n}{kd} \right \rfloor \cdot \left \lfloor \frac{m}{kd} \right \rfloor\cdot \mu(d)$

预处理$\mu(d)$的前缀和,再整除分块的思想求解即可

与yy的gcd那道题不同,整除分块的部分有一些细节需要思考

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define N 50100
 5 #define maxn 50000
 6 #define ll long long 
 7 using namespace std;
 8 
 9 int T,a,b,c,d,K,cnt;
10 int use[N],pr[N],mu[N],pmu[N];
11 void Pre()
12 {
13     mu[1]=1;
14     for(int i=2;i<=maxn;i++)
15     {
16         if(!use[i]) pr[++cnt]=i,mu[i]=-1;
17         for(int j=1;j<=cnt&&i*pr[j]<=maxn;j++){
18             use[i*pr[j]]=1;
19             if(i%pr[j]==0){    
20                 mu[i*pr[j]]=0;
21                 break;
22             }else{
23                 mu[i*pr[j]]=-mu[i];
24             }
25         }
26     }
27     for(int i=1;i<=maxn;i++)
28         pmu[i]=pmu[i-1]+mu[i];
29 }
30 ll solve(int n,int m)
31 {
32     if(n>m) swap(n,m);
33     ll ans=0;int nd,md;
34     for(int i=1,la,mi=min(n/K,m/K);i<=mi;i=la+1)
35     {
36         nd=n/K,md=m/K;
37         la=min(nd/(nd/i),md/(md/i));
38         ans+=1ll*(n/(K*i))*(m/(K*i))*(pmu[la]-pmu[i-1]);
39     }return ans;
40 }
41 int main()
42 {
43     scanf("%d",&T);
44     Pre();
45     for(int t=1;t<=T;t++)
46     {
47         scanf("%d%d%d%d%d",&a,&b,&c,&d,&K);
48         printf("%lld\n",solve(b,d)-solve(a-1,d)-solve(b,c-1)+solve(a-1,c-1));
49     }
50     return 0;
51 }

 

posted @ 2018-11-16 17:18  瓜皮大哥丶  阅读(...)  评论(...编辑  收藏