Problem
YY的GCD
TimeLimit:10Sec
MemoryLimit:512MB
Description
神犇YY虐完数论后给傻叉kAc出了一题:
给定N,M,求1≤x≤N,1≤y≤M且gcd(x,y)为质数的(x,y)有多少对
kAc这种傻叉必然不会了,于是向你来请教。
多组输入。
第一行一个整数T表述数据组数。
接下来T行,每行两个正整数,表示N,M。
Output
T行,每行一个整数表示第i组数据的结果。
Sample Output
HINT
T=104
N,M≤107
标签:莫比乌斯反演
Solution
套路反演+积性函数预处理。
先套路推一波反演式:
AnsLetf(x)thenAns=p∑i=1∑nj=1∑m[gcd(i,j)=p]=p∑i=1∑⌊n/p⌋j=1∑⌊m/p⌋d∣i,j∑μ(d)=p∑d=1∑⌊pmin(n,m)⌋μ(d)×⌊d⋅pn⌋×⌊d⋅pm⌋=T=1∑np∣T∑μ(pT)×⌊Tn⌋×⌊Tm⌋=T=1∑n⌊Tn⌋⌊Tm⌋p∣T∑μ(pT)=p∣T∑μ(pT),=T=1∑⌊Tn⌋⌊Tm⌋f(T)
那么我们需要用线筛预处理出所有f值。
对于当前预处理到的数x和枚举到的质数p,有
f(x)=d∣x,d∈pri∑μ(dx)f(x⋅p)=d∣x⋅p,d∈pri∑μ(dx⋅p)
下面的式子的一部分可以化为上面的式子,剩余部分直接加上去。
分类讨论:
- 若p∣x,则下式中d=p时,dx⋅p的分解式中p的指数一定大于1,于是只有d=p时会对答案产生μ(px⋅p)=μ(x)的贡献,所以f(x⋅p)=μ(x)。
- 若p∤x,则下式中对于任意d∣x,其贡献都为上式中对应项的贡献乘μ(p)=−1,即d∣x的贡献为f(x)。当d∤x时,只存在d=p,此时贡献为μ(x)。因此f(x⋅p)=μ(x)−f(x)。
由此,可以线筛预处理出所有f值,然后根号分块计算答案即可。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| #include <bits/stdc++.h> #define MAX_N 100000 using namespace std; typedef long long lnt; template <class T> inline void read(T &x) { x = 0; int c = getchar(), f = 1; for (; !isdigit(c); c = getchar()) if (c == 45) f = -1; for (; isdigit(c); c = getchar()) (x *= 10) += f*(c-'0'); } int pri[MAX_N+5], mu[MAX_N+5], fac[MAX_N+5], cnt; bool NotPri[MAX_N+5]; void PriS() { mu[1] = 1; for (int i = 2; i <= MAX_N; i++) { if (!NotPri[i]) pri[cnt++] = i, mu[i] = -1; for (int j = 0, x; j < cnt; j++) { if ((x = i*pri[j]) > MAX_N) break; NotPri[x] = true; if (i%pri[j]) mu[x] = -mu[i]; else {mu[x] = 0; break;} } } } int main() { int n; read(n), PriS(); lnt ans = 0LL; for (lnt i = 1, l, r; i < sqrt(n); i++) { cnt = 0; for (int j = 1; j <= sqrt(i); j++) if (i%j == 0) fac[cnt++] = j; for (l = 1; l < i; l = r+1) { lnt val = n/(i*(i+l)); if (!val) break; r = min(n/val/i-i, i-1); for (lnt k = 0, j; k < cnt; k++) { j = fac[k], ans += mu[j]*(r/j-(l-1)/j)*val; lnt t = i/j; if (i%t == 0 && (j^t)) ans += mu[t]*(r/t-(l-1)/t)*val; } } } return printf("%lld\n", ans), 0; }
|