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

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

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

约数个数定理就是:

对于一个大于1正整数n可以分解质因数

则n的正约数的个数就是

对于n^k其实就是每个因子的个数乘了一个K

然后现在就变成了求每个数的每个质因子有多少个,但是比赛的时候只想到sqrt(n)的分解方法,总复杂度爆炸,就一直没过去,然后赛后看官方题解感觉好妙啊!

通过类似素数筛法的方式,把L - R的质因子给分解,就可以在O(nlogn)的时间之内把所以的数给筛出来。

代码:

/** @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;
}

  

时间: 2024-10-25 07:18:24

HDU 6069 Counting Divisors(区间素数筛法)的相关文章

HDU 6069 Counting Divisors —— 2017 Multi-University Training 4

Counting Divisors Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)Total Submission(s): 2599    Accepted Submission(s): 959 Problem Description In mathematics, the function d(n) denotes the number of divisors of p

hdu 6069 Counting Divisors(求因子的个数)

Counting Divisors Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)Total Submission(s): 3170    Accepted Submission(s): 1184 Problem Description In mathematics, the function d(n) denotes the number of divisors of

第四场 hdu 6069 Counting Divisors (逆向思维)

http://acm.hdu.edu.cn/showproblem.php?pid=6069 题目大意:求 i 从 l 到 r 中 i 的k次方的因子数之和. 解题思路:我们可以知道一个数有因子,则这个数的因子一定是若干个质数因子排列组合得到的.我们首先要得到10^6中的素数,然后它的因子数量是 相同质因子数量+1 的乘积,所以我们能够想到从 l 到 r 枚举每一个i得到其 相同质因子数量+1 的乘积 的累加和.但是这样在枚举时会发现有一些质数是并不是所求的 i 的因子,所以我们应该反过来考虑,

HDU 6069 Counting Divisors(唯一分解定理+因子数)

http://acm.hdu.edu.cn/showproblem.php?pid=6069 题意: 思路: 根据唯一分解定理,$n={a_{1}}^{p1}*{a2_{}}^{p2}...*{a_{m}}^{pm}$,那么n的因子数就是 n的k次方也是一样的,也就是p前面乘个k就可以了. 先打个1e6范围的素数表,然后枚举每个素数,在[ l , r ]寻找该素数的倍数,将其分解质因数. 到最后如果一个数没有变成1,那就说明这个数是大于1e6的质数.(它就只有0和1两种选择) 1 #includ

hdu 6069 Counting Divisors

题意:给出求L,R 之间的数的K次方的因子数之和 思路:打表求出1~10^6之间的素数,枚举[L,R]之间素数的倍数,然后按算数基本定理求出因子个数和.处理过后[L,R]之间的数要么是1,要么是一个素数,再次根据算数基本定理计算因子个数和. #include<bits/stdc++.h> #define MAXSIZE 1000015 #define INF 0x3f3f3f3f #define LL long long #define MOD 998244353 using namespac

区间素数筛法

给定整数a和b,请问区间[a,b)内有多少个素数? a<b<=10^12 b-a<=10^6 因为b以内合数的最小质因数一定不超过sqrt(b),如果有sqrt(b)以内的素数表的话,就可以把筛选法用在[a,b)上了,先分别做好[2,sqrt(b))的表和[a,b)的表,然后从[2,sqrt(b))的表中筛得素数的同时,也将其倍数从[a,b)的表中划去,最后剩下的就是区间[a,b)内的素数了. 有的时候需要求出某个特定区间的素数,但是数可能很大,数组也开不小,所以需要进行下标偏移,这样才

LightOJ 1197 Help Hanzo(区间素数筛法)

#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cmath> using namespace std; #define maxn 50000 int vis[maxn], isprime[5200], num[100005], k; void prime()//只需要把[1,sqrt(2^31)]之间的素数筛选出来就ok了. {

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

洛谷 P1865 A % B Problem(简单区间素数) 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=1865 题目背景 题目名称是吸引你点进来的 实际上该题还是很水的 题目描述 区间质数个数 输入输出格式 输入格式: 一行两个整数 询问次数n,范围m 接下来n行,每行两个整数 l,r 表示区间 输出格式: 对于每次询问输出个数 t,如l或r∉[1,m]输出 Crossing the line 输入输出样例 输入样例#1: 2 5 1 3