[SDOI2015]约数个数和 莫比乌斯反演

~~~题面~~~

题解:

为什么SDOI这么喜欢莫比乌斯反演,,,

首先有一个结论$$d(ij) = \sum_{x|i}\sum_{y|j}[gcd(x, y) == 1]$$
为什么呢?
首先,可以看做从两个数中分别取一些不重叠的质数的$k_{i}$次方,组成新数的方案数。
那如果有需要重叠的部分怎么办?
可以看做全都在第一个or第二个数中取。
但是一个数的次数不够怎么办呢?
相当于以1为媒介,可以简介统计到这些情况
比如$2^{3} \cdot 2^{2}  = 2^{5}$可以看成$1, 2^{3}$ + $1, 2^{2}$,这样就可以做到分别枚举了指数从1到5的情况了;
$$ans = \sum_{i = 1}^{n}\sum_{j = 1}^{m}\sum_{x | i}\sum_{y | j}[gcd(x, y) == 1]$$
$$ans = \sum_{x = 1}^{n}\sum_{y = 1}^{m} \lfloor{\frac{n}{x}}\rfloor \lfloor{\frac{m}{y}}\rfloor [gcd(x, y) == 1]$$<---改成枚举x和y,然后统计有多少对i,j中分别含有因数x,y
设$$f(d) = \sum_{x = 1}^{n}\sum_{y = 1}^{m} \lfloor{\frac{n}{x}}\rfloor \lfloor{\frac{m}{y}}\rfloor [gcd(x, y) == d]$$, $$g(x) = \sum_{x | d}^{min(n, m)}{f(d)}$$
那么$ans = f(1)$
反演一下得到:$$f(n)  = \sum_{n | d}\mu(\frac{d}{n}) \cdot g(d)$$
接下来就是怎么求$g(d)$了。
$$g(d) = \sum_{x = 1}^{n}\sum_{y = 1}^{m} \lfloor{\frac{n}{x}}\rfloor \lfloor{\frac{m}{y}}\rfloor [d | gcd(x, y)]$$
$d | gcd(x, y)$ ---> $d | x + d | y$ ,因为$x | n + y | m$ ---> $d | n + d | m$
所以枚举$d_{i}$就符合条件了,$\lfloor{\frac{n}{dx}}\rfloor$ ---> $dx$倍数的个数,即有多少i,j的搭配是可以满足$[d|gcd(x, y)]$的
$$g(d) = \sum_{x = 1}^{ \lfloor{\frac{n}{d}}\rfloor }\sum_{y = 1}^{ \lfloor{\frac{m}{d}}\rfloor } \lfloor{\frac{n}{dx}}\rfloor \lfloor{\frac{m}{dy}}\rfloor$$
于是现在就是要求$f(1)$
$$f(1) = \sum_{d = 1}^{min(n, m)}{\mu(\frac{d}{1})g(d)}$$
$$= \sum_{d = 1}^{min(n, m)}{\mu(d)g(d)}$$
$$= \sum_{d = 1}^{min(n, m)}{\mu(d) \cdot \sum_{x = 1}^{ \lfloor{\frac{n}{d}}\rfloor }\sum_{y = 1}^{ \lfloor{\frac{m}{d}}\rfloor } \lfloor{\frac{n}{dx}}\rfloor \lfloor{\frac{m}{dy}}\rfloor}$$
这个式子可以整数分块。
设$N = \frac{n}{d}$, $M = \frac{m}{d}$,那么
$$= \sum_{d = 1}^{min(n, m)}{\mu(d) \cdot \sum_{x = 1}^{ N }\sum_{y = 1}^{ M } \lfloor{\frac{N}{x}}\rfloor \lfloor{\frac{M}{y}}\rfloor}$$
$$= \sum_{d = 1}^{min(n, m)}{\mu(d) \cdot \sum_{x = 1}^{ N}{\lfloor{\frac{N}{x}}\rfloor} \sum_{y = 1}^{M}  {\lfloor{\frac{M}{y}}\rfloor}}$$
而$N = \lfloor{\frac{n}{d}}\rfloor$, $M = \lfloor{\frac{m}{d}}\rfloor$有很多相同的区间段,所以可以整数分块求。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define R register int
 4 #define AC 50100
 5 #define ac 50000
 6 #define LL long long
 7 int n, m, tot, t;
 8 LL ans;
 9 int prime[AC];
10 LL mu[AC], s[AC];
11 bool z[AC];
12 
13 inline int read()
14 {
15     int x = 0;char c = getchar();
16     while(c > '9' || c < '0') c = getchar();//error!!!又一次打错了读入优化。。。是||啊
17     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
18     return x;
19 }
20 
21 void pre()
22 {
23     int x;
24     mu[1] = 1;
25     for(R i = 2; i <= ac; i++)
26     {
27         if(!z[i]) prime[++tot] = i, mu[i] = -1;
28         for(R j = 1; j <= tot; j++)
29         {
30             x = prime[j];
31             if(x * i > ac) break;
32             z[x * i] = true;
33             if(!(i % x)) break;
34             mu[i * x] = -mu[i]; 
35         }
36     }
37     for(R i = 1; i <= ac; i++) mu[i] += mu[i-1];    
38     int pos;
39     for(R i = 1; i <= ac; i++) 
40     {
41         for(R j = 1; j <= i; j = pos + 1)
42         {
43             pos = i / (i / j);
44             s[i] += (LL)(i / j) * (LL)(pos - j + 1);
45         }
46     }
47 //    for(R i = 1; i <= 30; i++) printf("%lld\n", s[i]);
48 }
49 
50 void work()
51 {
52     t = read();
53     while(t--)
54     {
55         n = read(), m = read(), ans = 0;
56         //scanf("%d%d", &n, &m);ans = 0;
57         int pos, b = min(n, m);
58         for(R i = 1; i <= b; i = pos + 1)
59         {
60             pos = min(n / (n / i), m / (m / i));
61             ans += (mu[pos] - mu[i - 1]) * s[n / i] * s[m / i];
62         }
63         printf("%lld\n", ans);
64     }
65 }
66 
67 int main()
68 {
69 //    freopen("in.in", "r", stdin);
70     pre();
71     work();
72 //    fclose(stdin);
73     return 0;
74 }

 

posted @ 2018-08-16 17:44  ww3113306  阅读(203)  评论(0编辑  收藏  举报
知识共享许可协议
本作品采用知识共享署名-非商业性使用-禁止演绎 3.0 未本地化版本许可协议进行许可。