• FZU 1969 GCD Extreme UESTC 1723 吴神的大脑


    Accept: 77    Submit: 136
    Time Limit: 1000 mSec    Memory Limit : 32768 KB

    Problem Description

    Given the value of N, you will have to find the value of G. The meaning of G is given in the following code

    G=0; 
    for(i=1;i<N;i++)
        for(j=i+1;j<=N;j++) 
            G+=gcd(i,j); 

    /*Here gcd() is a function that finds the greatest common divisor of the two input numbers*/

    Input

    The input file contains at most 20000 lines of inputs. Each line contains an integer N (1<N <1000001). The meaning of N is given in the problem statement. Input is terminated by a line containing a single zero.

    Output

    For each line of input produce one line of output. This line contains the value of G for the corresponding N. The value of G will fit in a 64-bit signed integer.

    Sample Input

    10 100 200000 0

    Sample Output

    67 13015 143295493160

    参考思想
    http://hi.baidu.com/aekdycoin/item/8095ba4eebb2d3eba5c066d2
    代码参考
    http://blog.csdn.net/duanxian0621/article/details/7847514
    G=0;
    
    for(k=1;k< N;k++)
    
    for(j=i+1;j<=N;j++)
    
    {
    
    G+=gcd(k,j);
    
    }
    显然如果O(n^2*gcd复杂度) ,一组数据就够你挂的了.
    因此我们必须优化优化再优化
    
    观察显然可以得到:
    G=
    gcd(1,2)+
    gcd(1,3)+gcd(2,3)+
    gcd(1,4)+gcd(2,4)+gcd(3,4)+
    .............................................................
    gcd(1,n)+gcd(2,n)+............................+gcd(n-1,n)
    
    
    于是得到G的公式
    
    
    
    为什么写成这种形式?是为了求解方便
    
    显然如果依然暴力套肯定还是超时
    
    于是我们考虑优化,因为这个公式还是很有特点的
    如果我们可以很快的得到下面的值(假设是G(n)),那么上面的公式通过预处理来得到解答,最后查询只需要O(1)
    
    
    这个如何计算?
    由于gcd(n,i) | n
    所以gcd(n,i)=k,k|n
    于是我们可以先得到n的所有因子,然后利用gcd(n,i)=k--->gcd(n/k,i/k)=1来求解
    即先求出满足gcd(n,i)=k的个数(Euler(n/k)),然后把个数直接乘上k就是这一部分的和,同理其他部分
    
    显然如果暴力分解肯定超时,于是考虑预处理
    1.预处理出1..1000000的Euler()
    2.预处理出1..1000000的G(n)
    3.预处理区间和
    然后就可以了
    预处理Euler()并不难,详见:
    http://hi.baidu.com/aekdycoin/blog/item/7055063fa5011a3a70cf6c30.html
    
    至于处理G(n),必须使用到预处理因子和的类似技巧.
    
    预处理因子和只需要用2个循环搞定(前提是规模不大,百万级别还是可以接受的)
    第1个循环,i,枚举1..sqrt(N)
    第2个循环,j,枚举j=k*i,在保证i*i<j的情况下,我们根据因子对称性可以知道
    dp[j]+=i+j/i;考虑到i*i=j的情况下我们只需要加一次,所以这时候dp[j]+=i;
    
    而类似的,这题也可以这么做,假设i为j的因子,那么显然有
    1.i*i<j
    G[j]+=Euler(i)*(j/i)+Euler(j/i)*i
    2.i*i==j
    G[j]+=Euler(i)*i


    学到了快速同时求很多欧拉函数的方法
    //还有利用欧拉函数求求1-n中所有数的最大公约数之和)

    #include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #define lson l,m,k<<1 #define rson m+1,r,k<<1|1 #define N 1000001 using namespace std; __int64 phi[N]; __int64 ans[N]; void init() { int i,j,k; for(i=2;i<N;i++) phi[i]=i; for(i=2;i<N;i++) if(phi[i]==i) for(j=i;j<N;j+=i) phi[j]=phi[j]/i*(i-1); for(i=2;i<N;i++) ans[i]=phi[i]; for(i=2;i<=1000;i++) { ans[i*i]+=phi[i]*i; for(j=i*i+i,k=i+1;j<N;j+=i,k++) ans[j]+=phi[k]*i+k*phi[i]; } for(i=3;i<N;i++) ans[i]+=ans[i-1]; } int main() { init(); int n; while(scanf("%d",&n),n) { printf("%I64d\n",ans[n]); } return 0; }
  • 相关阅读:
    bzoj 1588: [HNOI2002]营业额统计 treap
    Codeforces Round #135 (Div. 2) E. Parking Lot 线段数区间合并
    cdoj 851 方老师与素数 bfs
    hdu 5150 Sum Sum Sum 水
    Codeforces Round #376 (Div. 2) F. Video Cards 数学,前缀和
    POJ 1984 Navigation Nightmare 带全并查集
    POJ 1655 Balancing Act 树的重心
    POJ 3140 Contestants Division 树形DP
    HDU 3586 Information Disturbing 树形DP+二分
    HDU 1561 The more, The Better 树形DP
  • 原文地址:https://www.cnblogs.com/372465774y/p/2697772.html
Copyright © 2020-2023  润新知