码迷,mamicode.com
首页 > 其他好文 > 详细

[bzoj2818]: Gcd

时间:2017-09-25 19:48:46      阅读:142      评论:0      收藏:0      [点我收藏+]

标签:gcd   前缀   匹配   clu   欧拉   name   nbsp   ++   stream   

想了一下就秒了

大概算是欧拉函数里比较好想的题了

直接考虑$gcd(x,y) = 1$

因为互质就满足性质$gcd(x * p,y * p) = p$

所以就可以转化成欧拉函数了,就是求出互质对数然后对合法的素数匹配一下就行了

可以用前缀和优化

 

对于质数的处理我是直接在求欧拉函数的时候筛的

所以复杂度是$O(nloglogn)$的,但是不开O2貌似跑不过

楼下几位dalao的复杂度我不是很会算,不知道有没有dalao能解释一下

#include <cstdio>
#include <ctype.h>
#include <cstdlib>

#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

template <typename T>
inline T read(T &f){
    f = 0;
    int x = 1;
    char c = getchar();
    while(!isdigit(c)){
        if(c == -)
            x = -1;
        c = getchar();
    }
    while(isdigit(c))
        f = (f << 1) + (f << 3) + c - 0,c = getchar();
    return f = f * x;
}

#define LL long long

const int maxn = 10000000 + 5;

int n,tot;

LL S[maxn];
LL pri[maxn],phi[maxn];

LL ans;

void phi_table(){
    phi[1] = 1;
    for(int i = 2;i <= n;i ++)
        if(!phi[i]){
            pri[++ tot] = i;
            for(int j = i;j <= n;j += i){
                if(!phi[j]) phi[j] = j;
                phi[j] = phi[j] / i * (i - 1);
            }
        }
}

int main(){
    read(n);
    
    phi_table();

    for(int i = 1;i <= n;i ++)
        S[i] = S[i - 1] + phi[i];
    
    for(int i = 1;i <= tot;i ++)
        ans = ans + (S[n / pri[i]] << 1) - 1;

    printf("%lld\n",ans);
    return 0;
}

 

[bzoj2818]: Gcd

标签:gcd   前缀   匹配   clu   欧拉   name   nbsp   ++   stream   

原文地址:http://www.cnblogs.com/lin1043/p/7593505.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!