Frogs HDU - 5514
Posted Jozky86
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Frogs HDU - 5514相关的知识,希望对你有一定的参考价值。
题意:
有n个青蛙,第 i 个青蛙每次只能够跳 ai步,现在有m个石头围成一圈,编号为0到m−1,现在青蛙可以围着这个石头组成的圆跳无限次,每跳一次就会占领这个石头,可以无限占领,现在问你的是这n个青蛙占领的石头的编号的总和是多少。
题解:
参考博客
肯定和容斥有关,但本人很无擅长容斥,所以不会。。。
第一个方法(欧拉函数):
对于第i个青蛙,他所能跳的步长为gi=gcd(m,ai),也就是所有编号为gi的倍数的石头,他都能占领
现在有多个青蛙,就会存在一些位置被重复占领,所有我们要考虑容斥,为了消除这些重复的值,我们规定第i个石头只能由gcd(m,i)的步长来占领,例如环长为12,那么就有:
2,10 只能由步长为 2 的来占领;
3 , 9只能由步长为 3 的来占领;
4 , 8 只能由步长为 4 的来占领;
6 只能由步长为 6 的来占领;
这些步长都是<m的m的因子因子组成,我们先预处理出所有因子,然后判断该因子是否能被gcd(m,ai)中得一个整除(比如gcd=2,那么步长为2,4,6得都可以实现)
由步长为x所占石头的编号和为:
步长为2:2+10=2 * (1+5) = 2 * (phi[6] * 6/2)
步长为3:3+9=3 * (1+3)
步长为4:4+8=4 * (1+2)
步长为6:6=6 * 1
对于步长为x的求和就是x * (与m/x互素的个数的和),括号内的数是与m/x互质的数,因为gcd(m,ai)=gcd(12,9)=3,提出3后,gcd(4,3)等于1,所以3与12/3互质
结论:
在[1,x]中与x互素的数的和为:phi[x] * x/2(欧拉函数得性质)
整理得:x * phi[m/x] * m/2 * 2 = phi[m/x] * m/2
求和即可
第二个方法(容斥做法):
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
vector<int> G,fac;//G为所谓的”步长“ fac为因子
int getPhi(int n){
int m = (int)sqrt(n+0.5);
int ans = n;
for(int i = 2;i <= m;i++){
if(!(n%i)){
ans = ans/i*(i-1);
while(!(n%i)) n /= i;
}
}
if(n > 1) ans = ans/n*(n-1);
return ans;
}
int main(){
int T;cin>>T;
for(int TT = 1;TT <= T;TT++){
cout<<"Case #"<<TT<<": ";
fac.clear();
G.clear();
int n,m,x,tag = 0;cin>>n>>m;
for(int i = 0;i < n;i++){
cin>>x;
int g = __gcd(x,m);
if(g == 1)tag = 1;
G.push_back(g);
}
if(tag){
cout<<1ll*m*(m-1)/2<<endl;continue;
}
sort(G.begin(),G.end());
n = unique(G.begin(),G.end()) - G.begin();//去重
int mm = sqrt(m+0.5);
for(int i = 2;i <= mm;i++){
if(!(m%i)){
fac.push_back(i);
if(i*i != m) fac.push_back(m/i);
}
}
ll ans = 0;
for(int i = 0;i < fac.size();i++){
for(int j = 0;j < n;j++){
if(!(fac[i]%G[j])){
ans += 1ll*getPhi(m/fac[i])*m/2;
break;
}
}
}
cout<<ans<<endl;
}
return 0;
}
以上是关于Frogs HDU - 5514的主要内容,如果未能解决你的问题,请参考以下文章