HDU 6069 Counting Divisors(区间素数筛法)

题意:。。。就题面一句话

思路:比赛一看公式,就想到要用到约数个数定理

约数个数定理就是:

对于一个大于1正整数n可以分解质因数
则n的正约数的个数就是
对于n^k其实就是每个因子的个数乘了一个K
然后现在就变成了求每个数的每个质因子有多少个,但是比赛的时候只想到sqrt(n)的分解方法,总复杂度爆炸,就一直没过去,然后赛后看官方题解感觉好妙啊!
通过类似素数筛法的方式,把L - R的质因子给分解,就可以在O(nlogn)的时间之内把所以的数给筛出来。
代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/** @xigua */
#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <cstring>
#include <queue>
#include <set>
#include <string>
#include <map>
#include <climits>
#define PI acos(-1)
using namespace std;
typedef long long ll;
typedef double db;
const int maxn = 1e6 + 5;
const int mod = 998244353;
const int INF = 1e8 + 5;
const ll inf = 1e15 + 5;
const db eps = 1e-6;
bool is[maxn];
ll pri[maxn]; int cnt;
 
void init() {
    for (int i = 2; i < maxn; i++) {
        if (!is[i]) {
            pri[++cnt] = i; //素数筛
            for (int j = i + i; j < maxn; j += i)
                is[j] = 1;
        }
    }
}
 
ll fac[maxn], p[maxn];
 
void solve() {
    ll l, r, k; cin >> l >> r >> k;
    ll res = 0;
    //通过1 到 (r - l + 1)的数组来表示 l 到 r
    //fac代表当前数的因子个数,p代表当前数被分解之后的值
    for (ll i = l; i <= r; i++)
        fac[i-l+1] = 1, p[i-l+1] = i;
    for (int i = 1; i <= cnt; i++) {
        ll be;
        if (l % pri[i] == 0) be = l;
        else {
            be = l + (pri[i] - l % pri[i]); //找到筛法的起点,因为有些不是从l开始的
        }
        for (ll j = be; j <= r; j += pri[i]) { //枚举be到r
            //每次增加pri[i]就可以保证这个数肯定是pri[i]的倍数
            ll tmp = 0;
            while (p[j-l+1] % pri[i] == 0) {    //看当前质因数的个数
                tmp++;
                p[j-l+1] /= pri[i];
            }
            fac[j-l+1] = fac[j-l+1] * (k * tmp % mod + 1) % mod;
        }
    }
    for (ll i = l; i <= r; i++) {
         //素数
        if (p[i-l+1] != 1) fac[i-l+1] = fac[i-l+1] * (k  + 1) % mod;
        res = (res + fac[i-l+1]) % mod;
    }
    cout << res << endl;
}
 
int main() {
    int t = 1, cas = 1;
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    init();
    scanf("%d", &t);
    while(t--) {
       // printf("Case %d: ", cas++);
        solve();
    }
    return 0;
}

  

posted @   ost_xg  阅读(192)  评论(0编辑  收藏  举报
编辑推荐:
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
阅读排行:
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· Spring AI + Ollama 实现 deepseek-r1 的API服务和调用
· 数据库服务器 SQL Server 版本升级公告
· 程序员常用高效实用工具推荐,办公效率提升利器!
· C#/.NET/.NET Core技术前沿周刊 | 第 23 期(2025年1.20-1.26)
点击右上角即可分享
微信分享提示