51nod 1040 最大公约数之和(容斥思想)

题目来源:  rihkddd
基准时间限制:1 秒 空间限制:131072 KB 分值: 80  难度:5级算法题
给出一个n,求1-n这n个数,同n的最大公约数的和。比如:n = 6
1,2,3,4,5,6 同6的最大公约数分别为1,2,3,2,1,6,加在一起 = 15
Input
1个数N(N <= 10^9)
Output
公约数之和
Input示例
6
Output示例
15

题意很简单。

思路:你可以确定的是1到n这些数字与n的gcd一定是n的约数,那么n的约数,你先枚举出来。

假如是n=20,那么20的约数有:1,2,4,5,10,20;

 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20   (i)
 1  2  1  4  5  2  1  4  1 10   1   4   1  2   5   4   1  2   1 20   (gcd)

这些数字可以按照gcd的值进行分类。

1,2,4,5,10,20(及按约数分类,这一类有(20/约数)个)

1 2 4 5 10 20 (与20的gcd的剩余值)(剩余值:前面计算过的贡献就减去,留下剩余的gcd)

我先算约数为1的哪一类,有哪些数字与20的gcd是1的倍数,就有20/1个数字,所以20/1*1及为约数1的贡献值,

因为1算的是1-20中所有的数字都算了1,所有数字的gcd剩余值都要减去1,因为我已经把gcd分了类,所以只需要把这一类的gcd减去1即可,

1,2,4,5,10,20(及按约数分类)

1 1 3 4  9  19 (与20的gcd的剩余值)因为一部分1已经算过了,所以其他的gcd剩余要算的值都减去1

然后算约数为2的贡献,有10个数字gcd是包含2的(如2,4,6,8,...20,那么约数若是2的倍数,那么就要减去2计算过的gcd),20/2*1,这个是2的贡献

1,2,4,5,10,20(及按约数分类)

1 1 2 4  8  18(与20的gcd的剩余值)(4,10,20这几个约数是2的倍数所以gcd剩余值要减去1(这个1是2与20剩余的gcd))

然后算约数为4的贡献,有20/4个数字gcd是包含4的,20/4*2,这个是4的贡献

1,2,4,5,10,20(及按约数分类)

1 1 2 4  8  16(与20的gcd的剩余值(20这个约数是4的倍数所以gcd剩余值要减去2)

1,2,4,5,10,20(及按约数分类)

1 1 2 4  4  12(与20的gcd的剩余值

1,2,4,5,10,20(及按约数分类)

1 1 2 4   4   8(与20的gcd的剩余值

答案为20/1*1+20/2*1 +20/4*2 +20/5*4 +20/10*4 +20/20*8=72

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<string>
#include<algorithm>
#define inf 0x3f3f3f3f
#define LL long long
using namespace std;
int s[100001],ls=0;//存约数
int k[100001];//gcd剩余值
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i*i<=n;i++)
    {
        if(n%i) continue;
        s[ls++]=i;
        if(i*i!=n) s[ls++]=n/i;
    }
    sort(s,s+ls);
    for(int i=0;i<ls;i++)
        k[i]=s[i];
    LL sum=0;
    for(int i=0;i<ls;i++)
    {
        sum+=(LL)k[i]*n/s[i];
        for(int j=i+1;j<ls;j++)
        {
            if(s[j]%s[i]) continue;
            k[j]-=k[i];
        }
    }
    printf("%I64d\n",sum);
}














  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值