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}}\rfloor\lfloor{\frac{m}{d}}\rfloor$
    因为$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}}}\rfloor}\mu(d)g(dp_{i})$
    $= \sum_{i = 1}^{k}\sum_{d = 1}^{\lfloor{\frac{min(n, m)}{p_{i}}}\rfloor}\mu(d)\lfloor{\frac{n}{dp_{i}}\rfloor \lfloor{\frac{m}{dp_{i}}\rfloor}}$<---枚举每个$\mu(d)分别被每个质数统计了几次$
    $= \sum_{T = 1}^{min(n, m)} \lfloor{\frac{n}{T}}\rfloor \lfloor{\frac{m}{T}}\rfloor\sum_{k|T}{\mu(\frac{T}{k})}$<---枚举每个$\lfloor{\frac{n}{T}}\rfloor \lfloor{\frac{m}{T}}\rfloor$会给哪些$\mu$做贡献(哪些$\mu$会在某次被统计$\lfloor{\frac{n}{T}}\rfloor \lfloor{\frac{m}{T}}\rfloor$次)
    然后暴力枚举质数和系数,给对应的$\mu$做贡献(质数$p_{i}$给它的倍数做贡献),统计前缀和,对前面的$\lfloor{\frac{n}{T}}\rfloor \lfloor{\frac{m}{T}}\rfloor$进行整数分块处理

 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\n", 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 }

猜你喜欢

转载自www.cnblogs.com/ww3113306/p/9486079.html
今日推荐