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=lrd(ik))mod998244353

(∑i=lrd(ik))mod998244353

(∑i=lrd(ik))mod998244353

时间: 2024-10-27 08:34:02

hdu6069(简单数学+区间素数晒法)的相关文章

素数晒法

之前在解释求素数的一道习题时,提过一个方法,叫素数筛法.下面就对这种方法的过程进行详细的解读. 之前提到 假设所有待判断的数字的上限是L,声明一个长度为L+1的布尔数组A[L+1].用这个数组来表示对应下标的数字是不是素数.起初,将数组所有成员标记为1,然后按照某种方法将其中的非素数都标记为0即可,完成后的数组有这样的特征:所有素数为下标的成员内存的数字都是1,所有非素数为下标的成员内存的数字都是0.例如 :2 是素数,那么A[2]=1:4不是素数,那么A[4]=0.这样,判断一个数是不是素数,

【龙书笔记】用Python实现一个简单数学表达式从中缀到后缀语法的翻译器(采用递归下降分析法)

上篇笔记介绍了语法分析相关的一些基础概念,本篇笔记根据龙书第2.5节的内容实现一个针对简单表达式的后缀式语法翻译器Demo. 备注:原书中的demo是java实例,我给出的将是逻辑一致的Python版本的实现. 在简单后缀翻译器代码实现之前,还需要介绍几个基本概念. 1. 自顶向下分析法(top-down parsing) 顾名思义,top-down分析法的思路是推导产生式时,以产生式开始符号作为root节点,从上至下依次构建其子节点,最终构造出语法分析树.在具体实现时,它会把输入字符串从左到右

洛谷 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

HDU 2161 Primes (素数筛选法)

题意:输入一个数判断是不是素数,并规定2不是素数. 析:一看就很简单吧,用素数筛选法,注意的是结束条件是n<0,一开始被坑了... 不说了,直接上代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> using namespace std; typedef long long LL; const int maxn = 16000 + 10; int p

关于素数的快速查找——素数筛选法

利用素数筛选法进行素数的快速查找.原理很简单,素数一定是奇数,素数的倍数一定不是素数.思路如下: 预定义N表示10000,即表示查找10000以内的素数,首先定义数组prime[]对N以内的数进行标记,奇数存为1,偶数存为0,最终实现结果为素数的prime值为1,因此将prime[2]赋值为1(2是素数).之后利用for循环,对N以内的奇数进行遍历(注意for循环的条件控制),for里用if判断是否为素数(奇数),若是,执行内部嵌套的for循环判断该奇数是否为素数,若是则标记为1,若不是则pri

LightOJ 1197 LightOJ 1197(大区间素数筛选)

http://lightoj.com/volume_showproblem.php?problem=1197 题目大意: 就是给你一个区间[a,b]让你求这个区间素数的个数 但a.b的值太大没法直接进行素数筛选(没法开那么大的数组),我们可以将a当做0,将b当做b-a 这样求[a,b]之间就变成了求[0, b - a]之间,这样就可以开数组来筛选 下图是代码式子j = j + prime[i] - a % prime[i]的由来 #include<stdio.h> #include<ma

POJ 2689 Prime Distance 素数筛选法应用

题目来源:POJ 2689 Prime Distance 题意:给出一个区间L R 区间内的距离最远和最近的2个素数 并且是相邻的 R-L <= 1000000 但是L和R会很大 思路:一般素数筛选法是拿一个素数 然后它的2倍3倍4倍...都不是 然后这题可以直接从2的L/2倍开始它的L/2+1倍L/2+2倍...都不是素数 首先筛选出一些素数 然后在以这些素数为基础 在L-R上在筛一次因为 R-L <= 1000000 可以左移开一个1百万的数组 #include <cstdio>

POJ 3978 Primes(素数筛选法)

题目 简单的计算A,B之间有多少个素数 只是测试数据有是负的 //AC //A和B之间有多少个素数 //数据可能有负的!!! #include<string.h> #include<stdio.h> //素数筛选法 int pri[100000+10];//1 合数, 0 素数 void Prime() { memset(pri,0,sizeof(pri)); pri[1]=pri[0]=1; for(int i=2;i<50002;i++) { if(pri[i]==0)

POJ 2262 Goldbach&#39;s Conjecture(素数筛选法)

Description In 1742, Christian Goldbach, a German amateur mathematician, sent a letter to Leonhard Euler in which he made the following conjecture: Every even number greater than 4 can be written as the sum of two odd prime numbers. For example: 8 =