BZOJ 2705 Longge的问题 (欧拉函数)

思路:

根据n的范围我们发现,就算是线性的扫一遍也不行(1e9的复杂度太高了)。
所以考虑一种logn或者sqrt(n)的方法;

我们知道这种题多半是不能按照题意直接做,而是要考虑每个gcd对答案的贡献。
考虑n的因子i,以i为gcd的对答案的贡献即为 gcd(,n)==i 的个数乘以i。又因为这道题要算的gcd中有一个是固定值,所以我们可以考虑将之转化为欧拉函数,即,个数为Euler(n/i)。在这个区间里和n/i互质的数,在分别乘以i后,一定就满足 gcd(,n)==i

同时,我们注意到每当我们找到n的一个因子i,我们其实同时还获得了n的另一个因子n/i,所以我们就可以通过这个,将复杂度降到sqrt(n)了。

注意,如果n是一个完全平方数,那么记得减去多加的那个因子的一遍贡献。

ps:

对了,这道题由于n太大了,只能每次求euler函数的值,而不能用线性筛o(n)的求。

#include<stdio.h>
#include <iostream>
#include<string.h>
#include<math.h>
#include<algorithm>
#define eps 1e-8
typedef long long int lli;
using namespace std;
const int maxn = 1e6+10;
lli euler(lli n){
    lli res = n,x=n;;
    for(lli i = 2;i*i <= x; i++){
        if(x%i==0){
            res = res/i * (i-1);
            while(x%i==0){
                x/=i;
            }
        }
    }
    if(x!=1){
        res = res/x*(x-1);
    }
    return res;
}
int main(){
    lli p,q;
        lli a,b;
        scanf("%lld",&a);
        lli ans = 0;
        for(lli i = 1;i*i <= a;i++){
            if(a%i == 0){
                ans += i*euler(a/i)+ a/i*euler(i);
                if(i*i==a) ans-= a/i*euler(i);
            }
        }
        printf("%lld\n",ans);
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值