1. 程式人生 > >hdu6069(簡單數學+區間素數曬法)

hdu6069(簡單數學+區間素數曬法)

() ide mil play 1.5 posit open ref ostream

題目鏈接: http://acm.hdu.edu.cn/showproblem.php?pid=6069

題意: 給出 l, r, k.求:(lambda d(i^k))mod998244353,其中 l <= i <= r, d(i) 為 i 的因子個數.

思路:若 x 分解成質因子乘積的形式為 x = p1^a1 * p2^a2 * ... * pn^an,那麽 d(x) = (a1 + 1) * (a2 + 1) * ... * (an + 1) .顯然 d(x^k) = (a1 * k + 1) * (a2 * k + 1) * ... * (an * k + 1) .

但如果僅僅以此暴力求解的話是會 tle 的, 需要用下區間素數篩法並且在篩選區間內合數時將其質因分解,將 i 對答案的貢獻存儲到 sum 數組中,然後再遍歷一次統計素數對答案的貢獻並將所有貢獻累加起來即可.

代碼:

技術分享
 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #define ll long long
 5 using namespace std;
 6 
 7 const int MAXN = 1e6 + 10;
 8 const int mode = 998244353;
 9 int prime[MAXN], tag[MAXN], tot;
10 ll sum[MAXN], gel[MAXN];
11 
12 void get_prime(void){
13
for(int i = 2; i < MAXN; i++){ 14 if(!tag[i]){ 15 prime[tot++] = i; 16 for(int j = 2; j * i < MAXN; j++){ 17 tag[j * i] = 1; 18 } 19 } 20 } 21 } 22 23 ll Max(ll a, ll b){ 24 return a > b ? a : b; 25 } 26 27 int
main(void){ 28 get_prime(); 29 ll l, r; 30 int k, t; 31 scanf("%d", &t); 32 while(t--){ 33 scanf("%lld%lld%d", &l, &r, &k); 34 for(int i = 0; i <= r - l; i++){ 35 sum[i] = 1; //sum[i]記錄i+l對答案的貢獻 36 gel[i] = i + l; //將所有元素放到a數組裏 37 } 38 for(int i = 0; i < tot; i++){ 39 ll a = (l + prime[i] - 1) / prime[i] * prime[i]; 40 for(ll j = a; j <= r; j += prime[i]){ // 篩[l, r]內的合數 41 ll cnt = 0; 42 while(gel[j - l] % prime[i] == 0){ 43 cnt++; 44 gel[j - l] /= prime[i]; 45 } 46 sum[j - l] = sum[j - l] * (cnt * k + 1 % mode); 47 if(sum[j - l] >= mode) sum[j - l] %= mode; 48 } 49 } 50 ll sol = 0; 51 for(int i = 0; i <= r - l; i++){ 52 if(gel[i] != 1) sum[i] = sum[i] * (k + 1); 53 sol += sum[i]; 54 if(sol >= mode) sol %= mode; 55 } 56 printf("%lld\n", sol); 57 } 58 return 0; 59 }
View Code

(i=lrd(ik))mod998244353 (i=lrd(ik))mod998244353 (i=lrd(ik))mod998244353

hdu6069(簡單數學+區間素數曬法)