题意:
* 1≤Bi≤Ai
* For each pair( l , r ) ( 1≤l≤r≤n ) , gcd(bl,bl+1...br)≥2
思路:
题意很好理解,样例也很好做。
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.youkuaiyun.com/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 100010
typedef 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.youkuaiyun.com/acdreamers/article/details/8542292 莫比乌斯反演——ACdreamer
http://blog.youkuaiyun.com/u012860063/article/details/47686525 莫比乌斯反演 模板啊——tianyiming
http://blog.youkuaiyun.com/ACTerminate/article/details/76216345 hdu6053 TrickGCD [莫比乌斯函数] ——ACTerminate
碎碎念:
莫比乌斯函数...看了我两三天看得超级迷 0.0
F 和 f 什么的...现在还是很迷Orz
后来干脆直接看这道题以及题解了(摊手
不过这道题好歹还能算是...告一段落了吧