Frogs - HDU5514
Frogs - HDU5514
icpc沈阳2015的题目。
容斥原理和数论的应用。
题目大意为给你一个数组 a[i]a[i]a[i](a[i]a[i]a[i] 即为第 iii 只青蛙的步长) 和若干格子编号为 000 到 m−1m - 1m−1,对于任意的正整数 k,ik, ik,i,编号为 k∗a[i]modmk * a[i] \mod mk∗a[i]modm 的格子会被占用,问所有被占用的格子的编号之和。
首先对于一个 a[i]a[i]a[i],显然所有编号为 gcd(a[i],m)\gcd(a[i], m)gcd(a[i],m) 的倍数的格子会被占用,抛弃掉之前的 a[i]a[i]a[i] ,直接将 gcd(a[i],m)\gcd(a[i], m)gcd(a[i],m) 设为新的 a[i]a[i]a[i],这样的话,我们记 a[i]a[i]a[i] 的倍数组成的集合为 AiA_iAi,那么最终答案为 S(A1∪A2∪⋯∪An)S(A_1 \cup A_2 \cup \dots \cup A_n)S(A1∪A2∪⋯∪An),其中 S(A)S(A)S(A) 为集合 AAA 中所有元素的和。
这个东西显然可以用容斥做,我们记集合 {A1,A2,…,An}\{A_1, A_2, \dots, A_n\}{A1,A2,…,An} 的幂集为 UUU,那么我们可以枚举 UUU 中所有元素,写出来容斥原理的公式:
S(⋃i=1nAi)=∑B∈P(−1)∣B∣−1S(⋂Ai∈BAi)S(\bigcup_{i = 1}^nA_i) = \sum_{B \in P}(-1)^{|B| - 1}S(\bigcap_{A_i \in B}A_i) S(i=1⋃nAi)=B∈P∑(−1)∣B∣−1S(Ai∈B⋂Ai)
(不得不说容斥原理的公式写成这个样子真的简洁明了又暴力,直接枚举了 2n2^n2n 种集合)
首先需要明确的是,我们使用容斥原理一定是要有一个出发点的,就是对于某一类集合,我们可以快速统计出来这一类集合的答案之和,因为我们不可能花费 O(2n)O(2^n)O(2n) 的时间复杂度去枚举所有 AiA_iAi 的交集情况,在集合数繁多的情况下我们只能对这些集合进行分类合并。
对于本题来说,这个分类方法可以很自然地得出。
我们思考若干集合的交,例如 A1∩A3∩A6A_1 \cap A_3 \cap A_6A1∩A3∩A6,那么在这个集合中的元素一定是 a[1],a[3],a[6]a[1], a[3], a[6]a[1],a[3],a[6] 的公倍数,即一定是 lcm(a[1],a[3],a[6])lcm(a[1], a[3], a[6])lcm(a[1],a[3],a[6]) 的倍数,并且 000 到 mmm 内所有 a[1],a[3],a[6]a[1], a[3], a[6]a[1],a[3],a[6] 的公倍数一定在这个集合中。
对于任意一组集合的并皆是如此,并且,我们不难发现,由于 a[i]a[i]a[i] 都是 mmm 的因数,那么若干个 a[i]a[i]a[i] 的最小公倍数也一定是 mmm 的因数。
所以,我们不妨把集合按照最小公倍数分类来进行容斥。
首先,根据上面的结论,我们有:
S(⋂Ai∈BAi)=12lml(ml−1)=12m(ml−1)S(\bigcap_{A_i \in B} A_i) = \frac 12 l\frac ml(\frac ml - 1) = \frac 12m(\frac ml - 1) S(Ai∈B⋂Ai)=21llm(lm−1)=21m(lm−1)
其中 lll 为所有 Ai∈BA_i \in BAi∈B 的 iii 中 a[i]a[i]a[i] 的最小公倍数。
我们不妨设
l=LCM(B)=lcmAi∈Ba[i]l = LCM(B) = {lcm}_{A_i \in B} a[i] l=LCM(B)=lcmAi∈Ba[i]
那么我们就可以以对集合按照最小公倍数分类的方式重写容斥原理。
S(⋃i=1nAi)=∑l∣m∑B∈P[LCM(B)=l](−1)∣B∣−1S(⋂Ai∈BAi)S(\bigcup_{i = 1}^nA_i) = \sum_{l|m}\sum_{B \in P}[LCM(B) = l](-1)^{|B| - 1}S(\bigcap_{A_i \in B}A_i) S(i=1⋃nAi)=l∣m∑B∈P∑[LCM(B)=l](−1)∣B∣−1S(Ai∈B⋂Ai)
=∑l∣m∑B∈P[LCM(B)=l](−1)∣B∣−112m(ml−1)= \sum_{l|m}\sum_{B \in P}[LCM(B) = l](-1)^{|B| - 1}\frac 12m(\frac ml - 1) =l∣m∑B∈P∑[LCM(B)=l](−1)∣B∣−121m(lm−1)
=12m∑l∣m(ml−1)∑B∈P[LCM(B)=l](−1)∣B∣−1= \frac 12m\sum_{l|m}(\frac ml - 1)\sum_{B \in P}[LCM(B) = l](-1)^{|B| - 1} =21ml∣m∑(lm−1)B∈P∑[LCM(B)=l](−1)∣B∣−1
接下来,我们只需要考虑如何计算
∑B∈P[LCM(B)=l](−1)∣B∣−1\sum_{B \in P}[LCM(B) = l](-1)^{|B| - 1} B∈P∑[LCM(B)=l](−1)∣B∣−1
这一坨式子。
这里我们需要用到一个结论,也就是非常出名的莫比乌斯反演公式:
如果有函数 f(n),g(n)f(n), g(n)f(n),g(n) 满足:
g(n)=∑d∣nf(d)g(n) = \sum_{d|n}f(d) g(n)=d∣n∑f(d)
那么他们同时也满足:
f(n)=∑d∣nμ(nd)g(d)f(n) = \sum_{d|n}\mu(\frac nd)g(d) f(n)=d∣n∑μ(dn)g(d)
这是一个非常非常非常有用的结论,他可以允许我们在枚举最大公约数或最小公倍数时去掉最大/最小,改为枚举公约数或者公倍数。这里的 μ\muμ 是莫比乌斯函数,关于莫比乌斯反演在我另一篇博客中有讲解,可以移步去看,不过这里我们只需要知道这个结论就行了。
在这里,我们不妨设
f(l)=∑B∈P[LCM(B)=l](−1)∣B∣−1f(l) = \sum_{B \in P}[LCM(B) = l](-1)^{|B| - 1} f(l)=B∈P∑[LCM(B)=l](−1)∣B∣−1
那么我们不难发现对于
g(n)=∑d∣nf(d)g(n) = \sum_{d|n}f(d) g(n)=d∣n∑f(d)
来说,f(n)f(n)f(n) 表示所有最小公倍数为 nnn 的集合 BBB 的 (−1)∣B∣−1(-1)^{|B| - 1}(−1)∣B∣−1 的和,那么 g(n)g(n)g(n) 即表示所有公倍数为 nnn 的集合 BBB 的 (−1)∣B∣−1(-1)^{|B| - 1}(−1)∣B∣−1 的和。
我们通过求出来 g(n)g(n)g(n) 的式子,然后利用莫比乌斯反演的公式来间接求出 f(n)f(n)f(n) 的式子。
g(n)g(n)g(n) 的式子非常好求,我们只需要知道数组 a[i]a[i]a[i] 中为 nnn 的约数的数的个数即可,假设个数为 xxx。
那么这些约数中任意若干个约数组成的集合都满足公约数为 nnn,即
g(n)=∑i=1x(xi)(−1)i−1=1−(1−1)xg(n) = \sum_{i = 1}^x{x \choose i}(-1)^{i - 1} = 1 - (1 - 1)^x g(n)=i=1∑x(ix)(−1)i−1=1−(1−1)x
我们可以得到,当数组 a[i]a[i]a[i] 中为 nnn 的约数的个数为 000 时,g(n)=0g(n) = 0g(n)=0,否则 g(n)=1g(n) = 1g(n)=1。
我们把这个式子代入原式:
S(⋃i=1nAi)=12m∑l∣m(ml−1)f(l)S(\bigcup_{i = 1}^nA_i) = \frac 12m\sum_{l|m}(\frac ml - 1)f(l) S(i=1⋃nAi)=21ml∣m∑(lm−1)f(l)
=12m∑l∣m(ml−1)∑d∣lμ(ld)g(d)= \frac 12m\sum_{l|m}(\frac ml - 1)\sum_{d|l}\mu(\frac ld)g(d) =21ml∣m∑(lm−1)d∣l∑μ(dl)g(d)
我们不妨交换一下求和顺序,将 g(d)g(d)g(d) 提前,得到
S(⋃i=1nAi)=12m∑d∣mg(d)∑l∣mdμ(l)(mdl−1)S(\bigcup_{i = 1}^nA_i) = \frac 12m\sum_{d|m}g(d)\sum_{l|\frac md}\mu(l)(\frac m{dl} - 1) S(i=1⋃nAi)=21md∣m∑g(d)l∣dm∑μ(l)(dlm−1)
我们设
T(n)=∑d∣nμ(d)(nd−1)=∑d∣nμ(d)nd−∑d∣nμ(d)=ϕ(n)−e(n)T(n) = \sum_{d|n}\mu(d)(\frac nd - 1) = \sum_{d|n}\mu(d)\frac nd - \sum_{d|n}\mu(d) = \phi(n) - e(n) T(n)=d∣n∑μ(d)(dn−1)=d∣n∑μ(d)dn−d∣n∑μ(d)=ϕ(n)−e(n)
这里的 ϕ(n)\phi(n)ϕ(n) 是欧拉函数,e(n)e(n)e(n) 是单位函数,仅当 n=1n = 1n=1 时 e(n)=1e(n) = 1e(n)=1,否则 e(n)=0e(n) = 0e(n)=0。
如果你不知道什么是欧拉函数或者单位函数,那你就把它当做一个普通积性函数就可以了,我们仍可以通过积性函数的性质用筛法筛出来函数的值。
所以,最终答案为:
S(⋃i=1nAi)=12m∑d∣mg(d)T(nd)S(\bigcup_{i = 1}^nA_i) = \frac 12m\sum_{d|m}g(d)T(\frac nd) S(i=1⋃nAi)=21md∣m∑g(d)T(dn)
=12m∑d∣mg(d)[ϕ(nd)−e(nd)]= \frac 12m\sum_{d|m}g(d)[\phi(\frac nd) - e(\frac nd)] =21md∣m∑g(d)[ϕ(dn)−e(dn)]
这样,我们就可以先求出来 mmm 的所有约数,然后对于每个约数 ddd,求出来 g(d),ϕ(d)g(d), \phi(d)g(d),ϕ(d) 的值。
时间复杂度为 O(d(m)n)O(d(m)n)O(d(m)n),其中 d(m)d(m)d(m) 为 mmm 的因数个数,这个值很小,最大只有不到 400040004000 个(据说)。
然而最终代码还是跑得很快的,甚至只需要 71ms71ms71ms。
#include <bits/stdc++.h>const int MAXN = 1e5 + 5;int a[MAXN], ddiv[MAXN], g[MAXN], phi[MAXN], n, m, cnt, prime[MAXN], cnt2;int find(int x) {return std::lower_bound(ddiv + 1, ddiv + cnt + 1, x) - ddiv;
}int e(int x) {return x == 1;
}void solve(int T) {scanf("%d%d", &n, &m);cnt = cnt2 = 0;/*memset(g, 0, sizeof(g));memset(phi, 0, sizeof(phi));memset(ddiv, 0, sizeof(ddiv));memset(prime, 0, sizeof(prime));*/for(int i = 1; i <= n; i++) {int x;scanf("%d", &x);a[i] = std::__gcd(x, m);}std::sort(a + 1, a + n + 1);n = std::unique(a + 1, a + n + 1) - a - 1;for(int i = 1; i * i <= m; i++) {if(m % i != 0) continue;int d1 = i, d2 = m / i;ddiv[++cnt] = d1;if(d1 != d2) ddiv[++cnt] = d2;}std::sort(ddiv + 1, ddiv + cnt + 1);phi[1] = 1;for(int i = 2; i <= cnt; i++) {phi[i] = ddiv[i] - 1;for(int j = 1; j <= cnt2; j++) {if(ddiv[i] % prime[j] != 0) continue;int t1 = ddiv[i] / prime[j];if(t1 % prime[j] == 0) phi[i] = phi[find(t1)] * prime[j];else phi[i] = phi[find(t1)] * (prime[j] - 1);}if(phi[i] == ddiv[i] - 1) prime[++cnt2] = ddiv[i];}for(int i = 1; i <= cnt; i++) {g[i] = 0;for(int j = 1; j <= n; j++)if(ddiv[i] % a[j] == 0) {g[i] = 1; break;}}long long ans = 0;for(int i = 1; i <= cnt; i++) ans = ans + 1LL * g[i] * (phi[find(m / ddiv[i])] - (i == cnt));ans = ans * m / 2;printf("Case #%d: %lld\n", T, ans);
}int main() {int T;scanf("%d", &T);for(int i = 1; i <= T; i++) solve(i);return 0;
}
Frogs - HDU5514相关推荐
- HDU5514 Frogs
HDU5514 Frogs 题意:将\([0,m)\)所有符合\(a[i]*t ~mod~ m\)的值求和 做法: \(a[i]*t ~mod~ m\) 会在 \(gcd(a[i],m)\) 的倍数出 ...
- HDU-5514 Frogs
题目大意是给定一些(n)青蛙及其跳跃的步数和方法,给定一些石头,编号从1~m,问所有曾经被青蛙跳过的石头的编号的和. 思路 容斥定理 从题目中很容易得出每一个青蛙的跳过的石头编号是k * gcd(m, ...
- Frogs HDU - 5514
Frogs HDU - 5514 题意: 有n个青蛙,第 i 个青蛙每次只能够跳 ai步,现在有m个石头围成一圈,编号为0到m−1,现在青蛙可以围着这个石头组成的圆跳无限次,每跳一次就会占领这个石头 ...
- POJ 1659 Frogs#39; Neighborhood(度序列组成)
意甲冠军 中国 依据Havel-Hakimi定理构图即可咯 先把顶点按度数从大到小排序 可图的话 度数大的顶点与它后面的度数个顶点相连肯定是满足的 出现了-1就说明不可图了 #include ...
- 【论文笔记】Poison Frogs! Targeted Clean-Label Poisoning Attacks on Neural Networks
Poison Frogs! Targeted Clean-Label Poisoning Attacks on Neural Networks 引言 创新性 本篇论文的贡献(目的) 算法步骤 实验结果 ...
- POJ1659 Frogs' Neighborhood(Havel定理)
题目: Frogs' Neighborhood Time Limit: 5000MS Memory Limit: 10000K Total Submissions: 9932 Accepted ...
- hdoj 5514 Frogs
题目链接:Frogs 题目大意:有一个n个洞的圈,编号从0到m-1,然后有n只青蛙,起始为编号0,每次的步数是k步,问无限的时间后所有可以被青蛙访问的洞的编号 题目思路:我们可以很轻易的想到用gcd( ...
- codeforces 609F Frogs and mosquitoes 线段树+二分+multiset
http://codeforces.com/problemset/problem/609/F There are n frogs sitting on the coordinate axis Ox. ...
- HDU 5514 Frogs(欧拉函数+数论YY)
传送门 Frogs Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total ...
最新文章
- ios mysql 修改数据,iOS数据库FMDB--增删改查(模糊查询)实写记录
- python while循环语句-Python While 循环语句
- 转载——C语言中float,double类型,在内存中的结构(存储方式)
- 【栈】【856. 括号的分数】【中等】(需回顾)
- python怎么解释语言_python是解释型语言吗
- c:forEach varStatus属性
- C# 4.0 实现 Method Missing
- 你真的懂软件测试人员的痛苦吗?——目前软件测试5大误区
- mssql 动态行转列。
- 高标清上下变换器的测试评估及应用研究
- rockchip的pwm驱动框架
- Aliddns插件使用:小白超详细图文教程
- Mysql中有关Datetime和Timestamp的使用总结
- 解决easyui combobox赋值boolean类型的值时,经常出现的内容显示的value而不是text的bug...
- SVLAN,CVLAN,PVLAN区别
- html5账号秘密,JavaScript有关的10个秘密和怪癖
- nexus3的配置阿里云代理仓库
- 2022-2027年中国微光器件行业市场调查研究及投资战略研究报告
- 红灯停绿灯行c语言编程,基于物联网应用的《C语言程序设计》教学模式研究
- hypersion oracle_Oracle收购Hyperion(海波龙)带来的思考与机遇