1. 程式人生 > >計蒜客 30999 - Sum - [找規律+線性篩][2018ICPC南京網絡預賽J題]

計蒜客 30999 - Sum - [找規律+線性篩][2018ICPC南京網絡預賽J題]

isp alt square right 乘號 href 就是 sum int

題目鏈接:https://nanti.jisuanke.com/t/30999

技術分享圖片

樣例輸入
2
5
8


樣例輸出
8
14

題意:

squarefree數是指不含有完全平方數( 1 除外)因子的數,

現在一個數字 $n$,可以表示成兩個squarefree數 $a,b$ 相乘,即 $n = ab$,

假設 $f\left( n \right)$ 代表了 $n$ 分解成不同的數對 $\left( {a,b} \right)$ 的個數,

現在給你一個 $n$,要求 $f\left( 1 \right) + f\left( 2 \right) + \cdots + f\left( n \right)$。

題解:

不難發現,若 $n$ 含有一個因子是立方數乃至更高次方數,則此時 $f\left( n \right) = 0$,例如 $f\left( {2^3 \times 3} \right) = 0,f\left( {3^4 } \right) = 0$;

則剩下來的數,因子最多就是平方數,不妨舉些例子來看每個因子能提供多少貢獻:

最開始是 $f\left( 1 \right) = 1$,因為只有 $1 = 1 \times 1$,然後我們給它乘上一些因子……

  1、乘上指數為 $1$ 的因子,例如 $f\left( {1 \times 2} \right)$,加進來的 $2$ ,可以添加在原來$1 \times 1$的乘號左邊($2 \times 1$),也可以添加在右邊($1 \times 2$),所以貢獻了“$\times 2$”,即 $f\left( {1 \times 2} \right) = f\left( 1 \right) \times 2$;

  2、乘上指數為 $2$ 的因子,例如 $f\left( {1 \times 2^2 } \right)$,加進來的 $2^2$,它不能全部添加在某一邊,只能拆開來,一半添加在乘號左邊,一半添加在乘號右邊,即$2 \times 2$,所以貢獻了“$\times 1$”,即 $f\left( {1 \times 2^2} \right) = f\left( 1 \right) \times 1$。

那麽依次類推,再在後面乘上一些因子,同樣的道理,指數為 $1$ 則貢獻為“$\times 2$”,指數為 $2$ 則貢獻為“$\times 1$”。

很容易的就能得到遞推規律:假設 $n$ 的最小素因子是 $p$,則有 $n = m \times p^x$,我們分兩種情況討論:

  1、$x = 1$,$p$ 的貢獻為“$\times 2$”,就有 $f\left( n \right) = f\left( m \right) \times 2$;

  2、$x = 2$,$p$ 的貢獻為“$\times 1$”,就有 $f\left( n \right) = f\left( m \right)$;

那麽,現在的關鍵就是求得 $1$ 到 $2 \times 10^7$ 的每個數字的最小素因子,線性篩素數的時候可以順帶求出。

AC代碼:

#include<bits/stdc++.h>
using namespace std;

const int maxn=2e7+5;
const int MAX=2e7;

int n;
int mpf[maxn]; //存儲最小素因子

/************************** 線性篩 - st **************************/
int prime[maxn];
int isPrime[maxn];
void Screen() //歐拉篩法求素數
{
    register int cnt=0;
    memset(isPrime,1,sizeof(isPrime));
    isPrime[0]=isPrime[1]=0;
    for(int i=2;i<=MAX;i++)
    {
        if(isPrime[i]) prime[cnt++]=i, mpf[i]=i;
        for(int j=0;j<cnt;j++)
        {
            if(i*prime[j]>MAX) break;
            isPrime[i*prime[j]]=0, mpf[i*prime[j]]=prime[j];
            if(i%prime[j]==0) break;
        }
    }
}
/************************** 線性篩 - ed **************************/

long long f[maxn];

int main()
{
    Screen();

    f[1]=1;
    for(int i=2;i<=MAX;i++)
    {
        int mm = mpf[i];
        if((long long)mm*mm < MAX && (long long)mm*mm*mm < MAX && i%(mm*mm*mm) == 0) f[i]=0;
        else if((long long)mm*mm < MAX && i%(mm*mm) == 0) f[i]=f[i/mm/mm];
        else f[i]=2*f[i/mm];
    }
    for(int i=2;i<=MAX;i++) f[i]+=f[i-1];

    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        printf("%lld\n",f[n]);
    }
}

計蒜客 30999 - Sum - [找規律+線性篩][2018ICPC南京網絡預賽J題]