HDU 5514 Frogs(欧拉函数+数论YY)
2017-06-12 12:37
387 查看
传送门
Total Submission(s): 2198 Accepted Submission(s): 714
[align=left]Problem Description[/align] There are m stones lying on a circle, and n frogs are jumping over them.
The stones are numbered from 0 to m−1 and the frogs are numbered from 1 to n. The i-th frog can jump over exactly ai stones in a single step, which means from stone j mod m to stone (j+ai) mod m (since all stones lie on a circle).
All frogs start their jump at stone 0, then each of them can jump as many steps as he wants. A frog will occupy a stone when he reach it, and he will keep jumping to occupy as much stones as possible. A stone is still considered “occupied" after a frog jumped away.
They would like to know which stones can be occupied by at least one of them. Since there may be too many stones, the frogs only want to know the sum of those stones’ identifiers.
[align=left]Input[/align] There are multiple test cases (no more than 20), and the first line contains an integer t,
meaning the total number of test cases.
For each test case, the first line contains two positive integer n and m - the number of frogs and stones respectively (1≤n≤104, 1≤m≤109).
The second line contains n integers a1,a2,⋯,an, where ai denotes step length of the i-th frog (1≤ai≤109).
[align=left]Output[/align] For each test case, you should print first the identifier of the test case and then the sum of all occupied stones’ identifiers.
[align=left]Sample Input[/align]
[align=left]Sample Output[/align]
题目大意:
有 n 个青蛙,第 i 个青蛙每次只能够跳 ai 步,现在有 m 个石头围成一圈,编号为 0 到 m−1,现在青蛙可以围着这个石头组成的圆跳无限次,每跳一次就会占领这个石头,可以无限占领,现在问你的是这 n 个青蛙占领的石头的编号的总和是多少。
解题思路:
首先能够想到的是: 第 i 个青蛙能够跳的步长一定是 gi=GCD(m,ai),所以能占领的石头的编号就是 gi 的倍数,就拿第一个样例来说吧:
对于第一只青蛙来说 g1=GCD(12,9)=3,所以步长为 3, 那么他能跳的石头编号就是 0,3,6,9
对于第二只青蛙来说 g2=GCD(12,10)=2,所以步长为 2, 那么他能跳的石头编号就是 0,2,4,6,8,10
显然第一只青蛙和第二只青蛙占领的石头编号有重复的地方,那么我们为了消除这些重复的值,我们规定第 i 个石头只能由 GCD(m,i) 的步长的来占领。那么就有:
2,10 只能由步长为 2 的来占领;
3,9 只能由步长为 3 的来占领;
4,8 只能由步长为 4 的来占领;
6 只能由步长为 6 的来占领;
这样的话,就消除了重复的地方,现在问题就是怎么计算这样的和。
显然这些步长是由 <m 的 m 的因子组成,那么我们首先把这些因子预处理出来,然后判断该因子是否符合条件,即是不是能够被gcd(m,ai) 中的一个整除,在然后我们将这些步长当成公共因子提出来发现:
2+10=2∗(1+5)
3+9=3∗(1+3)
4+8=4∗(1+2)
6=6∗1
对于步长为 x 的求和来说,就是 x∗(与mx互素的个数的和)
需要知道一个结论:
在 [1,x] 中与 x 互素的数的和为: Phi(x)∗x2
那么显然有:
对于步长为 x 的求和来说,x∗Phi(mx)∗mx2
整理得:
Phi(mx)∗m2
所以最终的结果就是: ∑Phi(mx)∗m2
扩展:
对于在 [1,x] 中与 x 互素的数的和为: Phi(x)∗x2 的简单证明:
对于 gcd(x,i)=gcd(x,x−i)
那么就是成对出现的,不会出现相同的结果, 即i=x−i
假设这个成立那么有 x=2∗i, gcd(x,i)=i,与已知矛盾,所以不成立,
那么显然 gcd(x,i)=1 的个数为 Phi(x) 个,然后gcd(x,i)=1 的与 gcd(x,x−i)=1 的合并就有:
与 x 互素的和就是 Phi(x)∗x2
代码:
补:
现在更新一种容斥原理的做法,最开始的时候,我也想到容斥了,可是后来精度爆炸就没怎么想了,现在补一下:
现在我们已知 gi=gcd(m,ai), 我们还是考虑 m 的因子x,如果这个因子 x 符合条件,那么我们来计算 x 对答案做出的贡献: (mx−1)∗m2。
首先我们预处理出 m 的除了 1 和 m 的因子 fac[i],如果这个因子fac[i]%g[i]=0 的话(其中 g[i]为可能出现的最大公约数),那么我们将其用一个 vis 数组进行标记为 1,然后再用一个数组 num 记录当前因子对答案做过的贡献,初始值为 0,那么有第i 个因子做出的贡献为: (mx−1)∗m2∗(vis[i]−num[i])
因为可能有重复的,所以我们就对所有能够整除因子 fac[i] 的因子全都加上 vis[i]−num[i], 然后就可以计算答案了。
代码:
Frogs
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2198 Accepted Submission(s): 714
[align=left]Problem Description[/align] There are m stones lying on a circle, and n frogs are jumping over them.
The stones are numbered from 0 to m−1 and the frogs are numbered from 1 to n. The i-th frog can jump over exactly ai stones in a single step, which means from stone j mod m to stone (j+ai) mod m (since all stones lie on a circle).
All frogs start their jump at stone 0, then each of them can jump as many steps as he wants. A frog will occupy a stone when he reach it, and he will keep jumping to occupy as much stones as possible. A stone is still considered “occupied" after a frog jumped away.
They would like to know which stones can be occupied by at least one of them. Since there may be too many stones, the frogs only want to know the sum of those stones’ identifiers.
[align=left]Input[/align] There are multiple test cases (no more than 20), and the first line contains an integer t,
meaning the total number of test cases.
For each test case, the first line contains two positive integer n and m - the number of frogs and stones respectively (1≤n≤104, 1≤m≤109).
The second line contains n integers a1,a2,⋯,an, where ai denotes step length of the i-th frog (1≤ai≤109).
[align=left]Output[/align] For each test case, you should print first the identifier of the test case and then the sum of all occupied stones’ identifiers.
[align=left]Sample Input[/align]
3 2 12 9 10 3 60 22 33 66 9 96 81 40 48 32 64 16 96 42 72
[align=left]Sample Output[/align]
Case #1: 42 Case #2: 1170 Case #3: 1872
题目大意:
有 n 个青蛙,第 i 个青蛙每次只能够跳 ai 步,现在有 m 个石头围成一圈,编号为 0 到 m−1,现在青蛙可以围着这个石头组成的圆跳无限次,每跳一次就会占领这个石头,可以无限占领,现在问你的是这 n 个青蛙占领的石头的编号的总和是多少。
解题思路:
首先能够想到的是: 第 i 个青蛙能够跳的步长一定是 gi=GCD(m,ai),所以能占领的石头的编号就是 gi 的倍数,就拿第一个样例来说吧:
2 12 9 10
对于第一只青蛙来说 g1=GCD(12,9)=3,所以步长为 3, 那么他能跳的石头编号就是 0,3,6,9
对于第二只青蛙来说 g2=GCD(12,10)=2,所以步长为 2, 那么他能跳的石头编号就是 0,2,4,6,8,10
显然第一只青蛙和第二只青蛙占领的石头编号有重复的地方,那么我们为了消除这些重复的值,我们规定第 i 个石头只能由 GCD(m,i) 的步长的来占领。那么就有:
2,10 只能由步长为 2 的来占领;
3,9 只能由步长为 3 的来占领;
4,8 只能由步长为 4 的来占领;
6 只能由步长为 6 的来占领;
这样的话,就消除了重复的地方,现在问题就是怎么计算这样的和。
显然这些步长是由 <m 的 m 的因子组成,那么我们首先把这些因子预处理出来,然后判断该因子是否符合条件,即是不是能够被gcd(m,ai) 中的一个整除,在然后我们将这些步长当成公共因子提出来发现:
2+10=2∗(1+5)
3+9=3∗(1+3)
4+8=4∗(1+2)
6=6∗1
对于步长为 x 的求和来说,就是 x∗(与mx互素的个数的和)
需要知道一个结论:
在 [1,x] 中与 x 互素的数的和为: Phi(x)∗x2
那么显然有:
对于步长为 x 的求和来说,x∗Phi(mx)∗mx2
整理得:
Phi(mx)∗m2
所以最终的结果就是: ∑Phi(mx)∗m2
扩展:
对于在 [1,x] 中与 x 互素的数的和为: Phi(x)∗x2 的简单证明:
对于 gcd(x,i)=gcd(x,x−i)
那么就是成对出现的,不会出现相同的结果, 即i=x−i
假设这个成立那么有 x=2∗i, gcd(x,i)=i,与已知矛盾,所以不成立,
那么显然 gcd(x,i)=1 的个数为 Phi(x) 个,然后gcd(x,i)=1 的与 gcd(x,x−i)=1 的合并就有:
与 x 互素的和就是 Phi(x)∗x2
代码:
#include <iostream> #include <cstring> #include <cstdio> #include <cstdlib> #include <algorithm> using namespace std; typedef long long LL; const LL MAXN = 1e4+5; LL gcd(LL a, LL b){ if(b == 0) return a; return gcd(b, a%b); } LL a[MAXN], fac[MAXN], g[MAXN]; LL Phi(LL x){ LL ans = x; for(LL i=2; i*i<=x; i++){ if(x%i==0){ ans -= ans/i; while(x%i==0) x /= i; } } if(x > 1) ans -= ans/x; return ans; } int main() { int T; scanf("%d", &T); for(int cas=1; cas<=T; cas++){ int n; LL m; scanf("%d%lld",&n, &m); int ok = 0; for(int i=0; i<n; i++){ scanf("%lld",&a[i]); g[i] = gcd(a[i], m); if(g[i] == 1) ok = 1; } printf("Case #%d: ",cas); if(ok == 1){ printf("%lld\n",m*(m-1)/2); continue; } sort(g, g+n); n = unique(g, g+n) - g; int cnt = 0; for(LL i=2; i*i<=m; i++){ if(i*i == m) fac[cnt++] = m/i; else if(m%i==0) fac[cnt++] = i, fac[cnt++] = m/i; } sort(fac, fac+cnt); LL sum = 0; for(int i=0; i<cnt; i++){ for(int j=0; j<n; j++){ if(fac[i]%g[j] == 0){ sum += Phi(m/fac[i])*m/2; break; } } } printf("%lld\n",sum); } return 0; } /** 2 9 96 81 40 48 32 64 16 96 42 72 */
补:
现在更新一种容斥原理的做法,最开始的时候,我也想到容斥了,可是后来精度爆炸就没怎么想了,现在补一下:
现在我们已知 gi=gcd(m,ai), 我们还是考虑 m 的因子x,如果这个因子 x 符合条件,那么我们来计算 x 对答案做出的贡献: (mx−1)∗m2。
首先我们预处理出 m 的除了 1 和 m 的因子 fac[i],如果这个因子fac[i]%g[i]=0 的话(其中 g[i]为可能出现的最大公约数),那么我们将其用一个 vis 数组进行标记为 1,然后再用一个数组 num 记录当前因子对答案做过的贡献,初始值为 0,那么有第i 个因子做出的贡献为: (mx−1)∗m2∗(vis[i]−num[i])
因为可能有重复的,所以我们就对所有能够整除因子 fac[i] 的因子全都加上 vis[i]−num[i], 然后就可以计算答案了。
代码:
#include <iostream> #include <cstring> #include <cstdio> #include <cstdlib> #include <algorithm> using namespace std; typedef long long LL; const int MAXN = 1e4+5; LL gcd(LL a, LL b){ if(b == 0) return a; return gcd(b, a%b); } LL g[MAXN], fac[MAXN]; int tp[MAXN], num[MAXN], vis[MAXN]; int main() { int T; scanf("%d", &T); for(int cas=1; cas<=T; cas++){ int n; LL m; scanf("%d%lld",&n, &m); int ok = 0; for(int i=0; i<n; i++){ scanf("%lld",&g[i]); g[i] = gcd(g[i], m); if(g[i] == 1) ok = 1; } printf("Case #%d: ",cas); if(ok == 1){ printf("%lld\n",m*(m-1)/2); continue; } sort(g, g+n); n = unique(g, g+n) - g; memset(vis, 0, sizeof(vis)); memset(num, 0, sizeof(num)); int cnt = 0; for(LL i=2; i*i<=m; i++){ if(i*i == m) fac[cnt++] = m/i; else if(m%i==0) fac[cnt++] = i, fac[cnt++] = m/i; } sort(fac, fac+cnt); int cnt1 = 0; for(int i=0; i<n; i++){ if(!vis[i]){ tp[cnt1++] = g[i]; for(int j=0; j<n; j++) if(g[j]%g[i]==0) vis[j] = 1; } } memset(vis, 0, sizeof(vis)); for(int i=0; i<cnt; i++){ for(int j=0; j<cnt1; j++){ if(fac[i]%tp[j] == 0){ vis[i] = 1; break; } } } LL sum = 0; for(int i=0; i<cnt; i++){ if(num[i] != vis[i]){ sum += m*(m/fac[i]-1)/2*(vis[i]-num[i]); for(int j=i+1; j<cnt; j++) if(fac[j]%fac[i] == 0) num[j] = num[j] + vis[i] - num[i]; } } printf("%lld\n",sum); } return 0; }
相关文章推荐
- HDU 5514 Frogs (数论容斥)
- HDU - 5514 - Frogs 【完美使用欧拉函数 -> 也可容斥】
- hdu 5514 Frogs 2015沈阳区域赛 数论 欧拉 好题 开心的题
- 2018-01-15 HDU 5514 Ver.A 数论 GCD 欧拉函数 总结归纳
- HDU - 5514 Frogs 欧拉函数||容斥定理
- hdu 5514 Frogs 欧拉函数
- HDU 5514 Frogs (容斥+数论)
- hdu 5514 Frogs 容斥或欧拉函数
- HDU 5514 Frogs 欧拉函数
- HDU - 5514 Frogs (容斥)
- HDU 5514 Frogs 容斥
- Hdu 5514 Frogs (容斥原理)
- HDU 5514 Frogs (容斥定理)
- HDU 5514 Frogs(容斥)
- hdu 1659 综合数论+ 筛选欧拉函数 +质因子 +容斥原理
- HDU 5407 CRB and Candies(数论+yy)
- (hdu 2588 gcd)<数论—欧拉函数>
- HDU 1695 数论 容斥 欧拉函数 || 莫比乌斯反演
- HDU1695-GCD(数论-欧拉函数-容斥)
- hdu 4279Number(数论:推论+欧拉函数性质)