HDU6069 尤拉篩法 約數定理 計算技巧。

2021-09-29 09:06:28 字數 1829 閱讀 7464

鏈結

首先先引入乙個數論概念,約數定理。

約數定理:

首先同上,n可以分解質因數:n=p1a1×p2a2×p3a3*…*pkak,

由約數定義可知p1a1的約數有:p10, p1^1, p12…p1a1 ,共(a1+1)個;同理p2a2的約數有(a2+1)個…pkak的約數有(ak+1)個。

故根據乘法原理:n的約數的個數就是(a1+1)(a2+1)(a3+1)…(ak+1)。

題目大體思路:

d(n)裡n的取值最大10^12。

那麼要判斷它是不是素數只需計算到sqrt(n),所以打個10^6的素數表,如果它是個合數,就可以用打好的表裡的素數進行分解,如果是個素數,就一直分解計數。

遍歷和計算中的技巧:

陣列開到10^6,從l到r拿0到r-l對應。假設現在遍歷到prime[i],先找到l~r第乙個能整除prime[i]的數a[j-l],以此開始,每次下標加prime[i],在分解a[j-l]時一直除以prime[i]直到除不盡,這時已經消除了prime[i]因子,假如從2這個素因子開始分解,第一遍l-r的迴圈之後,l-r區間內所有的數都把2除乾淨了,之後在按下乙個素數開始同樣的操作。每次除完乙個素數之後都把分解的冪值算進s[j-l]中依次對應好。

跳出素數迴圈之後,然後開始遍歷所有的a[i-l]和s[i-l],遍歷一遍l-r區間的a陣列的元素是不是1,因為有可能無法整除的大數,你想想看,如果給定乙個數,十的十二次方不能整除他的開方那麼它一定是乙個大素數。算完把它加到ans裡面就能整體統計這個區間內的數一共有多少因子。

話不多說,直接上**。其實該說的話也說了,看**就能看懂了。

如有寫的不好的地方還望大佬指點,我只是乙個小菜鳥。

#include 

#include

#include

#include

#define ll long long

using namespace std;

//尤拉線性篩素數+約數定理+區間整體貢獻

//卡5000ms

//大體思想就是依次遍歷所有的素數,遍歷l-r區間時每個數都把當前的素數除乾淨.

//最後10^6次方以內的素數都無法被整除的話,那麼這個(10^12以內)的數一定是乙個素數.

const int maxn =

1000009

;const int mod =

998244353

;int prime[maxn]

;bool visited[maxn]

;ll s[maxn]

,a[maxn]

; int cnt;

void

getprime()

}}}}

int main()

for(ll i =

0;i < cnt;i++

) s[j-l]

=(s[j-l]*(

(k*cnt+1)

%mod)

)%mod;}}

ll ans =0;

for(ll i = l;i <= r;i++

) ans =

(ans + s[i-l]

)%mod;

}printf

("%lld\n"

,ans);}

return0;

}最後我這個**提交執行的時間4383ms,

其實素數篩可以篩到1e6,不用跟我一樣篩到1e7。

HDU 6069 素數篩法

思路 設 n p 1 p 2 p m n p 1 c 1 p 2 c 2 p m c m 則d n k kc 1 1 kc 2 1 kc m 1 d n c 1 1 c2 1 c m 1 則 d n k kc 1 1 kc 2 1 kc m 1 d n k kc 1 1 kc 2 1 k c m 1...

HDU6069 篩法 有新技巧

題目鏈結 解題思路 這道題是這是暑假集訓我debug時間最長的一道題,從昨天下午到今天中午。剛開始的時候直接列舉的l r之間的所有數的質因數,然後就tle了,後來我就看了一下題解,發現了一種優化方法,暴力的做法是把l r每個數的質因數都找一遍,這樣比如l r是1 8,4找過質因數2,6也找過質因數2...

HDU6069(思維 素數定理)

比賽的時候有想到一次找所有數的乙個共同因數,結果沒有考慮素數的情況,想歪了,成了莫比烏斯反演。素數定理 任意乙個數都可以表示為n pa11 pa22 pak k n的所有因子個數為 a 1 1 a2 1 ak 1 然後對與每個在範圍內的質數,都進行一次遍歷,看是不是l r中某些數的因子。明白了同時對...