Frogs HDU - 5514

Posted Jozky86

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Frogs HDU - 5514相关的知识,希望对你有一定的参考价值。

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的主要内容,如果未能解决你的问题,请参考以下文章

hdu 5514 Frogs(容斥)

hdu 5514Frogs

HDU_5514_Frogs

HDU 5514.Frogs-欧拉函数 or 容斥原理

HDU-5514 Frogs

hdu 5514 Frogs 容斥思想+gcd 银牌题