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);
}














發佈了156 篇原創文章 · 獲贊 56 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章