鏈結
首先先引入乙個數論概念,約數定理。
約數定理:
首先同上,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中某些數的因子。明白了同時對...