[SDOI2014]数表 莫比乌斯反演
题解:
设$f(d)$表示数$d$的约数和,那么$(i, j)$中的数为$f(gcd(i, j))$,
那么有2种枚举方法。
1,枚举每一格看对应的$f(d)$是几.$$ans = \sum_{i = 1}^{n}\sum_{j = 1}^{m}{f(gcd(i, j))}$$
2,枚举$d$看有哪些格子的$f$值为$f(d)$.
$$ans = \sum_{i = 1}^{min(n, m)}{f(d)}\sum_{x = 1}^{n}\sum_{y = 1}^{m}[gcd(x, y) == d]$$
显然后者更加方便。
所以$$ans = \sum_{i = 1}^{min(n, m)}{f(d)}\sum_{x = 1}^{n}\sum_{y = 1}^{m}[gcd(x, y) == d]$$
$$ans = \sum_{i = 1}^{min(n, m)}{f(d)}\sum_{x = 1}^{\lfloor{\frac{n}{d}}\rfloor}\sum_{y = 1}^{\lfloor{\frac{m}{d}}\rfloor}[gcd(x, y) == 1]$$
$$ans = \sum_{i = 1}^{min(n, m)}{f(d)}\sum_{x = 1}^{\lfloor{\frac{n}{d}}\rfloor}\sum_{y = 1}^{\lfloor{\frac{m}{d}}\rfloor}\sum_{t | gcd(x, y)}{\mu(t)}$$
$$\sum_{i = 1}^{min(n, m)}f(d)\sum_{t = 1}^{min(\lfloor{\frac{n}{d}}\rfloor, \lfloor{\frac{m}{d}}\rfloor)}{\lfloor{\frac{\lfloor{\frac{n}{d}}\rfloor}{t}}\rfloor}{\lfloor{\frac{\lfloor{\frac{m}{d}}\rfloor}{t}}\rfloor}\mu(t)$$<---看有多少对$(x, y)$统计到了$\mu(t)$(即为$\mu(t)$的倍数/有因子$\mu(t)$)
$$\sum_{i = 1}^{min(n, m)}f(d)\sum_{t =1}^{min(\lfloor{\frac{n}{d}}\rfloor, \lfloor{\frac{m}{d}}\rfloor)}{\lfloor{\frac{n}{td}\rfloor}}{\lfloor{\frac{m}{td}\rfloor}}\mu(t)$$
令$T = td$,则
$$ans = \sum_{T = 1}^{min(n, m)}{\lfloor{\frac{n}{T}}\rfloor \lfloor{\frac{m}{T}}\rfloor} \sum_{d|T}f(d)\mu(\frac{T}{d})$$
因为$T = td$,所以符合要求的$d$满足$d|T$.
设$$g(T) = \sum_{d | T}f(d)\mu(\frac{T}{d}) \Longleftrightarrow f(T) = \sum_{d | T}g(d)$$
则$$ans = \sum_{T = 1}^{min(n, m)}{\lfloor{\frac{n}{T}}\rfloor \lfloor{\frac{m}{T}}\rfloor} g(T)$$
但是由于有$a$的限制,对于不同的$a$,$g(T)$的值是不同的,因此先筛出$f$数组,然后将$f$按$f_{i}$排序,离线询问,一个一个把符合条件的$f(d)$加入$g$数组,也就是每次处理询问时再暴力将$f(d)$的贡献加给满足$d|T$的$g(T)$,但是由于要维护$g$数组的前缀和,因此用树状数组维护$g$数组
根据$f$数组的定义,
当$x\quad mod \quad p_{i} \quad != \quad 0$有$f(x \cdot P_{i}) = f(x) + f(x) \cdot P_{i}$,其中$P_{i}$是质数
否则有$f(x \cdot p_{i}) = f(x) \cdot p_{i} + f(t)$,其中$t$为$x$除去质因数$p_{i}$后的值
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define R register int 4 #define AC 101000 5 #define ac 100000 6 #define LL long long 7 #define p 2147483648LL 8 int t, tot, l; 9 int prime[AC], mu[AC]; 10 LL g[AC]; 11 bool z[AC]; 12 struct node{ 13 int n, m, a, id;LL ans; 14 }s[AC]; 15 struct kkk{ 16 int d; 17 LL w; 18 }f[AC]; 19 20 inline int read() 21 { 22 int x = 0;char c = getchar(); 23 while(c > '9' || c < '0') c = getchar(); 24 while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); 25 return x; 26 } 27 28 inline bool cmp(node a, node b) 29 { 30 return a.a < b.a; 31 } 32 33 inline bool cmp1(kkk a, kkk b) 34 { 35 return a.w < b.w; 36 } 37 38 inline int lowbit(int x) 39 { 40 return x & (-x); 41 } 42 43 inline void add(int x, int S) 44 { 45 // if(x <= 4)printf("add %d : %d\n", x, S); 46 for(R i = x; i <= ac; i += lowbit(i)) g[i] += S; 47 } 48 49 inline LL find(int x) 50 { 51 LL rnt = 0; 52 for(R i = x; i; i -= lowbit(i)) rnt += g[i]; 53 return rnt; 54 } 55 56 void pre() 57 { 58 t = read(); 59 for(R i = 1; i <= t; i++) 60 s[i].n = read(), s[i].m = read(), s[i].a = read(), s[i].id = i; 61 sort(s + 1, s + t + 1, cmp); 62 } 63 64 void get() 65 { 66 int x; 67 f[1] =(kkk){1, 1}, mu[1] = 1; 68 for(R i = 2; i <= ac; i++) 69 { 70 f[i].d = i; 71 if(!z[i]) prime[++tot] = i, f[i].w = i + 1, mu[i] = -1; 72 for(R j = 1; j <= tot; j++) 73 { 74 x = prime[j]; 75 if(x * i > ac) break; 76 z[x * i] = true; 77 if(!(i % x)) 78 { 79 int t = i; 80 while(!(t % x)) t /= x; 81 f[x * i].w = f[t].w + f[i].w * x; 82 break; 83 } 84 mu[x * i] = -mu[i]; 85 f[x * i].w = f[i].w + f[i].w * x; 86 } 87 } 88 sort(f + 1, f + ac + 1, cmp1); 89 } 90 91 void build(int a)//更新树状数组 92 { 93 for(R i = l + 1; i <= ac; i++) 94 { 95 if(f[i].w > a) return ; 96 ++l; 97 for(R j = f[i].d; j <= ac; j += f[i].d) 98 add(j, f[i].w * mu[j / f[i].d]); 99 } 100 } 101 102 inline bool cmp2(node a, node b) 103 { 104 return a.id < b.id; 105 } 106 107 void work() 108 { 109 for(R i = 1; i <= t; i++) 110 { 111 build(s[i].a); 112 int b = min(s[i].n, s[i].m), pos; 113 for(R j = 1; j <= b; j = pos + 1) 114 { 115 pos = min(s[i].n / (s[i].n / j), s[i].m / (s[i].m / j)); 116 s[i].ans += (s[i].n / j) * (s[i].m / j) * (find(pos) - find(j - 1)); 117 s[i].ans = (s[i].ans + p) % p;//取模error!!!取模的时候记得+p.... 118 }//error!!!无论何时都要+p并取模,,因为可能前面取模后再减就变负数了。。。。加个判断就应对不了负数的情况了 119 // printf("\n"); 120 } 121 sort(s + 1, s + t + 1, cmp2); 122 for(R i = 1; i <= t; i++) printf("%lld\n", s[i].ans); 123 } 124 125 int main() 126 { 127 freopen("in.in", "r", stdin); 128 //freopen("sdoi2014shb.in", "r", stdin); 129 //freopen("sdoi2014shb.out", "w", stdout); 130 pre(); 131 get(); 132 work(); 133 fclose(stdin); 134 //fclose(stdout); 135 return 0; 136 }