hdu6069(简单数学+区间素数筛法)
题目链接: 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 }
(∑i=l
(∑i=l
(∑i=l
我就是我,颜色不一样的烟火 --- geloutingyu