POJ2480——Longge's problem(数论,欧拉函数d)

本文介绍了一种解决Longge数学问题的有效算法。该问题要求计算从1到N的所有整数与N的最大公约数之和。文章通过巧妙地利用欧拉函数来减少计算复杂度,并提供了一个具体的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

Longge's problem
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 8050 Accepted: 2666

Description

Longge is good at mathematics and he likes to think about hard mathematical problems which will be solved by some graceful algorithms. Now a problem comes: Given an integer N(1 < N < 2^31),you are to calculate ∑gcd(i, N) 1<=i <=N. 

"Oh, I know, I know!" Longge shouts! But do you know? Please solve it. 

Input

Input contain several test case. 
A number N per line. 

Output

For each N, output ,∑gcd(i, N) 1<=i <=N, a line

Sample Input

2
6

Sample Output

3
15

大意:就是求[1,n]的整数和n的最大公约数的和

思路:肯定不能暴力。区间是[1,n],数是n,马上就想到欧拉函数。怎么联系起来?欧拉函数是求互质的数的个数。比如如果n能整除2,那么与n最大公约数为2的数的个数为区间[1,n/2]里头与n/2互质的数的个数。那么和就是phi[n/2]*2。

怎么降低复杂度呢?还是拿2举例子。n/2肯定也是n的约数,那么再加上phi[2]*n/2即可。

代码如下


#include <cmath>
#include <cstring>
#include <cstdio>
#include <vector>
#include <string>
#include <algorithm>
#include <string>
#include <set>
#include <cmath>


using namespace std;
typedef long long ll;
const int Max=100010;
ll p[Max];
bool is_prime[Max];

ll euler(ll n){
    ll res=n,a=n;
    for(int i=0;p[i]*p[i]<=a;i++){
        if(a%p[i]==0){
            res=res/p[i]*(p[i]-1);
            while(a%p[i]==0) a/=p[i];
        }
    }
    if(a>1) res=res/a*(a-1);
    return res;
}



int main()
{
    ll n;
    int k=0;
    for(int i=0;i<Max;i++)
        is_prime[i]=true;
    for(int i=2;i<Max;i++)
    {
        if(is_prime[i])
        {
            for(int j=2*i;j<Max;j+=i)
                is_prime[j]=false;
            p[k++]=i;
        }
    }
    while(scanf("%lld",&n)!=EOF)
    {
        ll sq=(int)sqrt((double)n);
        ll ans=0;
        for(int i=1;i<=sq;i++)
        {
            if(i*i==n)
            {
                ans+=euler(i)*i;
            }
            else if(n%i==0)
            {
                long long s=n/i;
                ans+=euler(s)*i+euler(i)*s;
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}














评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值