zoukankan      html  css  js  c++  java
  • GCD

    /**
    题目:GCD - Extreme (II)
    链接:https://vjudge.net/contest/154246#problem/O
    题意:
    for(i=1;i<N;i++)
        for(j=i+1;j<=N;j++)
        {
            G+=gcd(i,j);
        }
    思路:
    设f[n] = gcd(1,n)+gcd(2,n)+gcd(3,n)+...+gcd(n-1,n);
    s[n] = f[1]+f[2]+...+f[n];
    则:s[n] = f[n]+s[n-1];
    
    f[n]的约数个数一般少于n-1个。所以如果可以以约数归类,就可以减少计算量。
    设:gcd(n,i)表示 gcd(x,n) = i 时候的x的个数。(i为n的约数)
    又:gcd(x,n)=i => gcd(x/i,n/i)=1;那么x/i的个数为(n/i)的欧拉函数值phi(n/i);
    那么:f[n] = sum(i*phi(n/i)) (i为n的约数)
    求每个f[n]不需要对每一个n单独求约数。
    可以利用素数筛法类似的做法来处理。
    
    参考思路:lrj算法经训练指南P125
    */
    
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    const int maxn = 4e6+100;
    ll f[maxn], s[maxn];
    int phi[maxn];
    void phiTable()
    {
        for(int i = 1; i < maxn; i++) phi[i] = i;
        for(int i = 2; i < maxn; i+=2) phi[i]/=2;
        for(int i = 3; i < maxn; i+=2){
            if(phi[i]==i){
                for(int j = i; j < maxn; j+=i){
                    phi[j] = phi[j]/i*(i-1);
                }
            }
        }
    }
    void init()
    {
        for(int i = 1; i < maxn; i++){
            for(int j = i*2; j < maxn; j+=i){
                f[j] += i*phi[j/i];
            }
        }
        for(int i = 2; i < maxn; i++) s[i] = s[i-1]+f[i];
    }
    int main()
    {
        int T, cas=1, N;
        phiTable();
        init();
        while(scanf("%d",&N)==1&&N)
        {
            printf("%lld
    ",s[N]);
        }
        return 0;
    }
  • 相关阅读:
    小X的密码破译
    小X的加法难题
    足球联赛
    机器分配
    化装晚会
    Soundex编码
    迷之阶梯
    使用JMeter做压力测试
    SCOI 2010 序列操作
    动态求区间K大值(权值线段树)
  • 原文地址:https://www.cnblogs.com/xiaochaoqun/p/6653430.html
Copyright © 2011-2022 走看看