YY的GCD 莫比乌斯反演

~~~题面~~~

题解:

$ans = sum_{x = 1}^{n}sum_{y = 1}^{m}sum_{i = 1}^{k}[gcd(x, y) == p_{i}]$其中k为质数个数
    $$ans = sum_{i = 1}^{k}sum_{x = 1}^{n}sum_{y = 1}^{m}[gcd(x, y) == p_{i}]$$
    设$f(d)$表示$x$从$1$到$n$,$y$从$1$到$m$,$gcd == d$的个数,$g(d)$表示相同条件下$d | gcd$(即$gcd$为$d$的倍数)的个数
    那么$$f(d) = sum_{x = 1}^{n}sum_{y = 1}^{m}[gcd(x, y) == d]$$,$$g(d) = lfloor{frac{n}{d}} floorlfloor{frac{m}{d}} floor$$
    因为$$g(x) = sum_{x|d}^{min(n, m)}f(d)$$
    所以反演一下。
    $$f(x) = sum_{x | d}^{min(n, m)}mu(frac{d}{x})g(d)$$
    那么$ans = sum_{i = 1}^{k}f(p_{i})$
    $$= sum_{i = 1}^{k}sum_{x | d}^{min(n, m)}mu(frac{d}{x})g(d)$$
    改成直接枚举系数
    $$= sum_{i = 1}^{k}sum_{d = 1}^{lfloor{frac{min(n, m)}{p_{i}}} floor}mu(d)g(dp_{i})$$
    $$= sum_{i = 1}^{k}sum_{d = 1}^{lfloor{frac{min(n, m)}{p_{i}}} floor}mu(d)lfloor{frac{n}{dp_{i}} floor lfloor{frac{m}{dp_{i}} floor}}$$<---枚举每个$mu(d)分别被每个质数统计了几次$
    $$= sum_{T = 1}^{min(n, m)} lfloor{frac{n}{T}} floor lfloor{frac{m}{T}} floorsum_{k|T}{mu(frac{T}{k})}$$<---枚举每个$lfloor{frac{n}{T}} floor lfloor{frac{m}{T}} floor$会给哪些$mu$做贡献(哪些$mu$会在某次被统计$lfloor{frac{n}{T}} floor lfloor{frac{m}{T}} floor$次)
    然后暴力枚举质数和系数,给对应的$mu$做贡献(质数$p_{i}$给它的倍数做贡献),统计前缀和,对前面的$lfloor{frac{n}{T}} floor lfloor{frac{m}{T}} floor$进行整数分块处理

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define R register int
 4 #define AC 10000100
 5 #define LL long long 
 6 int n, m, tot, t;
 7 int prime[AC], mu[AC];
 8 LL s[AC], ans;
 9 bool z[AC];
10 
11 inline int read()
12 {
13     int x = 0;char c = getchar();
14     while(c > '9' || c < '0') c = getchar();
15     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
16     return x;
17 }
18 
19 void pre()
20 {
21     int now;
22     mu[1] = 1;
23     for(R i = 2; i <= 10000000; i++)
24     {
25         if(!z[i]) prime[++tot] = i, mu[i] = -1;
26         for(R j = 1; j <= tot; j++)
27         {
28             now = prime[j];
29             if(i * now > 10000000) break;
30             z[i * now] = true;
31             if(!(i % now)) break;            
32             mu[now * i] = -mu[i];
33         }
34     }
35     int p;
36     for(R i = 1; i <= tot; i++)//枚举质数 
37     {
38         p = prime[i];//卡常
39         for(R j = p; j <= 10000000; j += p) //枚举倍数
40             s[j] += mu[j / p];//or j = 系数, s[j * prime[i]] += mu[j];
41     }
42     for(R i = 1; i <= 10000000; i++) s[i] += s[i - 1];
43 }
44 
45 void work()
46 {
47     t = read();
48     while(t--)
49     {
50         int pos = 0;
51         ans = 0;
52         n = read(), m = read();
53         int b = min(n, m);//这里要取min!!!
54         for(R i = 1; i <= b; i = pos + 1)
55         {
56             pos = min(n / (n / i), m / (m / i));
57             ans += (LL) (n / i) * (LL) (m / i) * (LL) (s[pos] - s[i - 1]);//error 只有ans是LL是不够的
58         }        
59         printf("%lld
", ans);
60     }
61 }
62 
63 int main()
64 {
65 //    freopen("in.in", "r", stdin);
66     //freopen("YYnoGCD.in", "r", stdin);
67     //freopen("YYnoGCD.out", "w", stdout);
68     pre();
69     work();
70     //fclose(stdin);
71     //fclose(stdout);
72     return 0;
73 }
原文地址:https://www.cnblogs.com/ww3113306/p/9486079.html