2017多校联合第二场 1009题 hdu 6053 TrickGCD (超详细!!!)莫比乌斯 容斥
来源:互联网 发布:红警3 for mac版 编辑:程序博客网 时间:2024/04/29 17:02
题目链接
题意:
*
* For each pair( l , r ) (
思路:
题意很好理解,样例也很好做。
A 数组为 4 4 4 4 时,考虑
1) gcd = 2, 有 2 * 2 * 2 * 2 = 16 种
2) gcd = 3, 有 1 * 1 = 1 种
3) gcd = 4, 在前面考虑过了,故不再重复计算
故一共有 16 + 1 = 17 种
其实这里说的并不严谨,事实上我们讨论的并不是 gcd = x, 而是 x | gcd, 在第一类讨论 gcd = 2 时尤为明显。
事实上 2 * 2 * 2 * 2 算的是 2 = x | gcd 的种数,因为 4 4 4 4 的这种情况,其 gcd 事实上是 4 而并非 2.
所以说,我们上面的分类讨论只是十分直观浅显粗浅的分类。
不过大概意思已经出来了,对于每一个 x,去算 PI (i = 1 ~ n) (a[i] / x), 再对重复计算的部分进行一些处理,求个和,就是最后的答案。
然而这里说的一些处理还是太笼统了,我怎么知道要怎么处理呢?
我们先换个话题,来看一看莫比乌斯函数的定义。
(来源:http://blog.csdn.net/acdreamers/article/details/8542292)
莫比乌斯函数定义如下:
(1)若,那么
(2)若,均为互异素数,那么
(3)其它情况下
是不是看起来有些莫名其妙?
先不管它,我们来对刚刚那道题要算的 x 举几个例子:
考虑算到 x = 4 | gcd 时的情况,因为算 x = 2 | gcd 已经包括了这种情况,所以 x = 4 时可以不用计算
考虑算到 x = 6 | gcd 时的情况,因为算 x = 2 | gcd 时包括了一次该情况,算 x = 3 | gcd 时又包括了一次该情况,所以算 x = 6 时应该减去算出来的结果
考虑算到 x = 12 | gcd 时的情况,因为算 x = 2 | gcd 时包括了一次该情况,算 x = 3 | gcd 时包括了一次该情况,算 x = 4 | gcd 时没有计算,算 x = 6 | gcd 时减去了一次重复的该情况,总共恰好算了一次,所以 x = 12 | gcd 时也可以不用计算。
大概看出了一些规律:
如果当前算的 x 是素数,那么肯定是第一次算,所以当前需要加上一次。
如果当前算的 x 是两个相异素数的乘积 x = p1 * p2,那么算 p1 时加过一次,算 p2 时加过一次,所以当前需要减去一次。
如果当前算的 x 是三个相异素数的乘积 x = p1 * p2 * p3,那么算 p1 时加过一次,算 p2 时加过一次,算 p3 时加过一次,算 p1 * p2 时减过一次,算 p2 * p3 时减过一次,算 p3 * p1 时减过一次,1 + 1 + 1 - 1 - 1 - 1 = 0,所以当前需要加上一次。
……
如果当前算的 x 是 k 个相异素数的乘积 x = p1 * p2 * ... * pk,那么在之前的计算中
算一个素数时加上过 C(k, 1) 次,算两个素数时减去过 C(k, 2) 次,...,算 m 个素数时加/减过 C(k, m) 次
总共计算过 C(k, 1) - C(k, 2) + C(k, 3) - ... + ((-1) ^ k) * C(k, k - 1)
= (1 - 1) ^ k + C(k, 0) - ((-1) ^ (k + 1)) * C(k, k)
= 0 + 1 - (-1) ^ (k + 1)
= 1 - (-1) ^ (k + 1)
为使总共计算次数为 1 次,当前需要弥补的计算次数为 1 - (1 - (-1) ^ (k + 1)) = (-1) ^ (k + 1).
诶嘿,是不是和上面的莫比乌斯函数靠上一点了?
继续。
由算数基本定理可知,任意的自然数 x = (p1 ^ a1) * (p2 ^ a2) * (p3 ^ a3) * ... * (pk ^ ak),
除去我们上面讨论过的情况,其余的情况就是 至少存在一个 ai 使得 ai > 1 的情况了。
假设 x = (p1 ^ a1) * (p2 ^ a2) * (p3 ^ a3) * ... * (pk ^ ak),
我们考虑对应的 x' = p1 * p2 * p3 * ... * pk,
由上面的计算过程,最终我们使得 x' | gcd 的情况总计被计算过一次,
又因为 x' | x, 所以 x | gcd 的情况迄今也总计被计算过一次,这就恰好达成了总计计算 1 次的目标。
所以,此时的计算次数为 0 次,与莫比乌斯函数的形式再次一拍即合。
所以,我们可以说,莫比乌斯函数 μ(x) 即为
算到 x 时,使得 x 总计被计算一次 的 补偿系数(雾)
(其实就是方便容斥...)
细节上有一点需要注意的,那就是 μ(x) 事实上与我们刚才说的在大小上是反的,所以是减去而不是加上,
分析到这里,我们就知道每个对应的 x 应该被计算多少次了,那就是 -μ(x) 次
(看到这里没有看懂的童鞋请再回去看几遍前面讲的 或者 再自己手算几个简单的例子啦~)
这道题的另一个注意点就是先预处理一下读入的 a[i], 毕竟如果对于每个 x 都要算 1e5 个 a[i] / x 的乘积,时间代价还是太大了。
因为有很多 a[i] / x 会落到同一个区间中,所以可以统计 a[i] 的个数,前缀和处理一下,sum[m] 表示大小为 [0, m] 的区间内有多少个数,
那么 sum[x * (i + 1) - 1] - sum[x * i - 1] 即表示 a[ ] / x = i 的数的个数,快速幂一下,这部分的乘积就有了.
AC代码如下:
#include <bits/stdc++.h>#define maxn 100010typedef long long LL;inline int min(int a, int b) { return a < b ? a : b; }inline int max(int a, int b) { return a > b ? a : b; }int kas, prime[maxn], cnt[maxn], mu[maxn];bool check[maxn];const LL mod = 1e9 + 7;void Mobius() { memset(check, 0, sizeof(check)); mu[1] = 1; int tot = 0; for (int i = 2; i <= maxn; ++i) { if (!check[i]) { prime[tot++] = i; mu[i] = -1; } for (int j = 0; j < tot; ++j) { if (i * prime[j] > maxn) break; check[i * prime[j]] = true; if (i % prime[j] == 0) { mu[i * prime[j]] = 0; break; } else { mu[i * prime[j]] = -mu[i]; } } }}LL poww(LL a, LL b) { LL ret = 1; while (b) { if (b & 1) ret = ret * a % mod; a = a * a % mod; b >>= 1; } return ret;}void work() { int n; scanf("%d", &n); int minn = maxn + 10, maxx = 0; memset(cnt, 0, sizeof(cnt)); for (int i = 0; i < n; ++i) { int x; scanf("%d", &x); ++cnt[x]; minn = min(minn, x); maxx = max(maxx, x); } for (int i = 1; i <= maxn; ++i) cnt[i] += cnt[i - 1];// for (int i = 1; i <= 100; ++i) printf("%d ", cnt[i]); LL ans = 0; for (int i = 2; i <= minn; ++i) { if (mu[i] == 0) continue; LL mul = 1; for (int j = 1; i * j <= maxx; ++j) { int up = min(i * (j + 1), maxx + 1); int num = cnt[up - 1] - cnt[i * j - 1]; mul *= poww(j, num); mul %= mod; } ans = (ans - mu[i] * mul + mod) % mod;// printf("%lld\n", mul); } printf("Case #%d: %lld\n", ++kas, ans);}int main() { Mobius(); int T; scanf("%d", &T); while (T--) work(); return 0;}
参考:
http://blog.csdn.net/acdreamers/article/details/8542292 莫比乌斯反演——ACdreamer
http://blog.csdn.net/u012860063/article/details/47686525 莫比乌斯反演 模板啊——tianyiming
http://blog.csdn.net/ACTerminate/article/details/76216345 hdu6053 TrickGCD [莫比乌斯函数] ——ACTerminate
碎碎念:
莫比乌斯函数...看了我两三天看得超级迷 0.0
F 和 f 什么的...现在还是很迷Orz
后来干脆直接看这道题以及题解了(摊手
不过这道题好歹还能算是...告一段落了吧
- 2017多校联合第二场 1009题 hdu 6053 TrickGCD (超详细!!!)莫比乌斯 容斥
- 2017多校训练赛第二场 HDU 6053 TrickGCD(容斥原理/莫比乌斯反演)
- 2017多校第二场 HDU 6053 TrickGCD 莫比乌斯反演
- HDU 2017 多校联合训练赛2 1009 6053 TrickGCD 莫比乌斯函数
- 2017 杭电多校联赛第二场 1009 TrickGCD(容斥原理) HDU 6053
- 2017多校第二场 HDU 6053 TrickGCD 容斥,素数,思维
- hdu 6053 TrickGCD 容斥 莫比乌斯
- hdu 6053 TrickGCD 【容斥&筛法|莫比乌斯】
- hdu 6053 TrickGCD(容斥,分段,莫比乌斯函数)
- hdu 6053 TrickGCD 容斥原理(莫比乌斯工具)
- HDU 6053 TrickGCD 【容斥定理】【莫比乌斯函数】
- 【 hdu 6053】 TrickGCD 【数论 容斥 + 莫比乌斯函数 】
- 2017 Multi-University Training Contest 2 && HDOJ 6053 TrickGCD 【容斥+莫比乌斯函数】
- 2017 多校训练第二场 HDU 6053 TrickGCD
- HDU6053-TrickGCD 容斥原理+莫比乌斯反演
- hdu6053 TrickGCD 莫比乌斯函数 容斥原理
- TrickGCD(莫比乌斯函数,容斥)
- HDU 6053 TrickGCD (莫比乌斯函数)
- 如何去Tocat官网下载tomcat
- eclipse xml editor从视图编辑改为源代码编辑
- 贝叶斯思维(实例1)——贝叶斯基础框架
- 线程八锁示例
- Java服务端支付功能模块--(一)支付宝支付
- 2017多校联合第二场 1009题 hdu 6053 TrickGCD (超详细!!!)莫比乌斯 容斥
- 线程池ThreadPool使用示例
- 面向对象的三大特性
- Relatives【POJ2407】
- weblogic详解
- 团队协作工具调研笔记
- MaterialDesign学习篇(四),如何使用TabLayout
- MyBatis随笔
- 自学ThinkPHP--(二)URL和路由(上)