zoukankan      html  css  js  c++  java
  • HDU 5514 Frogs 欧拉函数

    题意:

    (m(1 leq m leq 10^9))个石子排成一圈,编号分别为(0,1,2 cdots m-1)
    现在在(0)号石头上有(n(1 leq n leq 10^4))只青蛙。第(i)只青蛙每次能往前跳(a_i)步,但是他们跳的次数不加限制。
    如果一块石头能至少被一只青蛙跳上去,那么称这块石头被占领了。
    求所有可能被占领的石头的编号和。

    分析:

    首先我们应该发现这样一个事实:

    每次向前跳(a_i)步的效果和跳(GCD(a_i, m))步是一样的

    所以可以对每个(a_i)(m)求个(GCD),然后排序去重,这样(a_i)的数量就会很少。
    在第一个样例中,(m=12),求完(GCD)(a_i)((2, 3))
    那么被(2)占领的石块的编号为((0, 2, 4, 6, 8, 10));被(3)占领的石块的编号为((0, 3, 6, 9))
    显然这样是有重复的,(6)号石块既会被(2)占领,又会被(3)占领。

    HDU 5528 Count a * b这题一样,为了避免算重,我们规定:

    编号为(i)的石块只会被步长为(GCD(i, m))的青蛙占领

    在这之前我们还要预处理一下:
    找出(m)所有的约数,然后用一个标记数组标记这些约数中存在哪些步长的青蛙。还要把所有步长的倍数也都标记上,也就是说有一个步长为(d)的青蛙,如果(kd)也是(m)的约数,我们可以假设还有一只步长为(kd)的青蛙存在。因为这样并不影响最终的结果。

    还是上面那个例子,对于步长为(2)的青蛙,我们只统计((2,10))这两个石块。其他的((4,8))这两个石块会在步长为(4)的青蛙中统计,((6))这个石块会在步长为(6)的青蛙中统计上。

    一般地,对于步长为(d)的青蛙,我们要统计的石块的个数就是([1,frac{m}{d}])互质的个数,即(phi(frac{m}{d}))
    这些石块的编号和为(d cdot frac{frac{m}{d} phi(frac{m}{d})}{2}=mfrac{phi(frac{m}{d})}{2})

    解释一下上面公式
    其实我们只需要证明这样一条公式:

    (n > 1)时,([1,n])中与(n)互质的数字之和为:(frac{n phi(n)}{2})

    证明
    因为(GCD(n,i)=GCD(n,n-i)),所以如果有(GCD(n,i)=1),那么也一定有(GCD(n,n-i)=1)成立。
    所以满足(GCD(n,i)=1)的数都是成对出现的,而且它俩的和为(n)
    还要证明一下,这样不会算重,也就是不会出现(i=n-i)的情况。
    因为如果(i=n-i Rightarrow n=2i),得到(n)是偶数,(i=frac{n}{2})。显然(GCD(n,i) eq 1),推出矛盾。
    上面是针对(n>2)的情况,幸运的是,(n=2)也满足这条公式。
    证毕。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    #include <map>
    #define MP make_pair
    using namespace std;
    
    typedef long long LL;
    typedef pair<int, int> PII;
    const int maxp = 32000;
    
    int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
    
    int pcnt;
    int prime[maxp], phi[maxp];
    bool vis[maxp];
    
    void preprocess() {
        for(int i = 2; i < maxp; i++) {
            if(!vis[i]) {
                prime[pcnt++] = i;
                phi[i] = i - 1;
            }
            for(int j = 0; j < pcnt && i * prime[j] < maxp; j++) {
                vis[i * prime[j]] = true;
                if(i % prime[j] == 0) {
                    phi[i * prime[j]] = phi[i] * prime[j];
                    break;
                }
                else phi[i * prime[j]] = phi[i] * (prime[j] - 1);
            }
        }
    }
    
    LL Phi(int n) {
        if(n < maxp) return phi[n];
        LL ans = 1;
        for(int i = 0; i < pcnt; i++) {
            if(prime[i] * prime[i] > n) break;
            for(int j = 0; n % prime[i] == 0; j++) {
                if(!j) ans *= (prime[i] - 1);
                else ans *= prime[i];
                n /= prime[i];
            }
        }
        if(n > 1) ans *= (n - 1);
        return ans;
    }
    
    const int maxn = 10000 + 10;
    int n, m;
    int a[maxn];
    
    vector<PII> divide;
    vector<int> factors;
    bool occupied[maxn];
    
    void dfs(int d, int x) {
        if(d == divide.size()) {
            factors.push_back(x);
            return ;
        }
        int p = divide[d].first, e = divide[d].second;
        for(int i = 0; i <= e; i++) {
            dfs(d+1, x);
            x *= p;
        }
    }
    
    int main()
    {
        preprocess();
    
        int T; scanf("%d", &T);
        for(int kase = 1; kase <= T; kase++) {
            printf("Case #%d: ", kase);
    
            scanf("%d%d", &n, &m);
            for(int i = 0; i < n; i++) {
                scanf("%d", a + i);
                a[i] = gcd(m, a[i]);
            }
            sort(a, a + n);
            n = unique(a, a + n) - a;
    
            if(a[0] == 1) { printf("%lld
    ", (LL)m * (m-1) / 2); continue; }
            
            divide.clear();
            int t = m;
            for(int i = 0; i < pcnt; i++) {
                if(prime[i] * prime[i] > t) break;
                if(t % prime[i] == 0) {
                    int cnt = 0;
                    while(t % prime[i] == 0) {
                        t /= prime[i];
                        cnt++;
                    }
                    divide.push_back(MP(prime[i], cnt));
                }
            }
            if(t > 1) divide.push_back(MP(t, 1));
            factors.clear();
            dfs(0, 1);
            sort(factors.begin(), factors.end());
            int sz = factors.size();
    
            memset(occupied, false, sizeof(occupied));
            for(int i = 0; i < n; i++) {
                int k = lower_bound(factors.begin(), factors.end(), a[i]) - factors.begin();
                occupied[k] = true;
            }
            for(int i = 1; i < sz; i++) if(!occupied[i])
                for(int j = 0; j < i; j++) if(factors[i] % factors[j] == 0 && occupied[j]) {
                    occupied[i] = true;
                    break;
                }
    
            LL ans = 0;
            for(int i = 0; i < sz - 1; i++) if(occupied[i]) {
                int t = m / factors[i];
                ans += (LL)m * Phi(t) / 2;
            }
    
            printf("%lld
    ", ans);
        }
    
        return 0;
    }
    
  • 相关阅读:
    ff与ie 的关于js兼容性
    CSS清除浮动的方法
    java8 LocalDateTime
    BigDecimal
    JAVA将 Word 文档转换为 PDF
    Ionic4
    SpringBoot后端统一格式返回
    SpringBoot集成JWT
    Java Lombok
    SpringBoot 中通过 CORS 解决跨域问题
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4939910.html
Copyright © 2011-2022 走看看