HDOJ 6069 素数筛法(数学)

Counting Divisors

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 3041    Accepted Submission(s): 1130

Problem Description

In mathematics, the function d(n) denotes the number of divisors of positive integer n.

For example, d(12)=6 because 1,2,3,4,6,12 are all 12‘s divisors.

In this problem, given l,r and k, your task is to calculate the following thing :

(∑i=lrd(ik))mod998244353

Input

The first line of the input contains an integer T(1≤T≤15), denoting the number of test cases.

In each test case, there are 3 integers l,r,k(1≤l≤r≤1012,r−l≤106,1≤k≤107).

Output

For each test case, print a single line containing an integer, denoting the answer.

Sample Input

3
1 5 1
1 10 2
1 100 3

Sample Output

10
48
2302

Source

2017 Multi-University Training Contest - Team 4

思路:先将1000005以内的素数打表(素数筛法O(n)).  然后将每个数拆成S=p1^a1*p2*^a2...*pn^an 的形式则 d(S)=(1+a1)*(1+a2)....*(1+an);

实现方法:1.用num[] 存下当前拆分后剩下的数字

     2.用ans[i]存下第i个数字此时的已拆分的累乘结果

     3.将素数从小到大扫一遍,对[l,r]每个数字进行拆分,逐一更新ans[i]的值

代码:

 1 #include<bits/stdc++.h>
 2
 3 typedef long long ll;
 4 using  namespace std;
 5
 6 const int N=1e6+5;
 7 const int inf=1e9;
 8 const int mod=998244353;
 9
10 ll l,r,k;
11 bool v[N];
12 ll ans[N];
13 ll num[N];
14 int pri[N];
15 int pcnt;
16 void init()
17 {
18     pcnt = 0;//素数筛
19     for(int i = 2; i <= N; i++)
20     {
21         if(!v[i])
22             pri[pcnt++] = i;
23         for(int j = 0; j < pcnt && pri[j] <= N/i; j++)
24         {
25             v[i*pri[j]] = 1;
26             if(i % pri[j]==0) break;
27         }
28     }
29 }
30 void f()
31 {
32     for(ll i=l;i<=r;i++)//初始化记录数组
33         num[i-l]=i,ans[i-l]=1;
34 }
35 int main()
36 {
37     int t;
38     init();
39     scanf("%d",&t);
40     while(t--)
41     {
42         scanf("%lld%lld%lld",&l,&r,&k);
43         f();
44         for(int i=0;i<pcnt&&pri[i]<=1000000;i++){//限制质因子大小
45             ll p=pri[i];
46             ll d=l/p+(l%p>0);
47             if(d==1) d=2;//l<=p 的情况在最后判断处理
48             for(ll j=d*p;j<=r;j+=p){
49                 ll cnt=0;
50                 while(num[j-l]%p==0){
51                     num[j-l]/=p;
52                     cnt++;
53                 }
54                 ans[j-l]=(ans[j-l]%mod)*((1+k*cnt)%mod)%mod;
55             }
56         }
57         ll sum=0;
58         for(ll i=l;i<=r;i++){
59             if(num[i-l]>1)//还存在一个大于1000000的因子,再乘上k+1
60                 sum=(sum+ans[i-l]*(k+1))%mod;
61             else
62                 sum=(sum+ans[i-l])%mod;
63         }
64         printf("%lld\n",sum);
65     }
66
67 }
时间: 2024-08-04 14:29:48

HDOJ 6069 素数筛法(数学)的相关文章

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

题意:...就题面一句话 思路:比赛一看公式,就想到要用到约数个数定理 约数个数定理就是: 对于一个大于1正整数n可以分解质因数: 则n的正约数的个数就是 对于n^k其实就是每个因子的个数乘了一个K 然后现在就变成了求每个数的每个质因子有多少个,但是比赛的时候只想到sqrt(n)的分解方法,总复杂度爆炸,就一直没过去,然后赛后看官方题解感觉好妙啊! 通过类似素数筛法的方式,把L - R的质因子给分解,就可以在O(nlogn)的时间之内把所以的数给筛出来. 代码: /** @xigua */ #i

hdu6069[素数筛法] 2017多校3

/*hdu6069[素数筛法] 2017多校3*/ #include <bits/stdc++.h> using namespace std; typedef long long LL; LL l, r, k; const LL MOD = 998244353LL; int T, n, prime[1100000], primesize; bool isprime[11000000]; void getlist(int listsize) { memset(isprime, 1, sizeof

POJ_3421_X-factor Chains(素数筛法)

X-factor Chains Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5659   Accepted: 1786 Description Given a positive integer X, an X-factor chain of length m is a sequence of integers, 1 = X0, X1, X2, -, Xm = X satisfying Xi < Xi+1 and Xi

poj 2478 Farey Sequence(基于素数筛法求欧拉函数)

http://poj.org/problem?id=2478 求欧拉函数的模板. 初涉欧拉函数,先学一学它基本的性质. 1.欧拉函数是求小于n且和n互质(包括1)的正整数的个数.记为φ(n). 2.欧拉定理:若a与n互质,那么有a^φ(n) ≡ 1(mod n),经常用于求幂的模. 3.若p是一个质数,那么φ(p) = p-1,注意φ(1) = 1. 4.欧拉函数是积性函数: 若m与n互质,那么φ(nm) = φ(n) * φ(m). 若n = p^k且p为质数,那么φ(n) = p^k - p

NowCoder猜想(素数筛法+位压缩)

在期末被各科的大作业碾压快要窒息之际,百忙之中抽空上牛客网逛了逛,无意中发现一道好题,NowCoder猜想,题意很明显,就是个简单的素数筛法,但竟然超内存了,我晕(+﹏+)~  明明有 3 万多 k 的空间限制……于是我不打表,试了试最暴力的做法,赤裸裸的做法果然超时了,无奈,只好对素数筛法进行位压缩了,这是我目前所能想到的方法了,第一次用上这样的特技,还是调了好一会(位数组里不能用 bool 来定义,具体的话好像 bool 和 int 之类的整型稍有不同:也不能用 int,因其最高位是正负标志

【POJ3006】Dirichlet&#39;s Theorem on Arithmetic Progressions(素数筛法)

简单的暴力筛法就可. 1 #include <iostream> 2 #include <cstring> 3 #include <cmath> 4 #include <cctype> 5 #include <cstdio> 6 #include <cmath> 7 #include <algorithm> 8 #include <numeric> 9 using namespace std; 10 11 co

poj 3518 Prime Gap 二分查找下界和素数筛法

/* 题意:输入有多组数据,每组数据一个n,如果n是素数,输出0否则输出离n最近的两个素数的积,第100000个素数是1299709,所有的素数都在这个范围内 思路:素数筛法加二分查找下界 */ #include<stdio.h> int a[1299720],pri[100005]; int Serch(int v)//二分查找下界 { int mid,x=0,y=100001; while(x<y) { mid=(y+x)/2; if(pri[mid]>=v) y=mid; e

hdu5391 Zball in Tina Town(素数筛法)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5391 题目大意:一个球初始体积为1,一天天变大,第一天变大1倍,第二天变大2倍,第n天变大n倍.问当第 n-1天的时候,体积变为多少.注意答案对n取模. 思路:题目意思搞了好久,其实就是第一天是1,第二天是1*2,第三天是1*2*3,也就是当第n天的时候是n!.那么答案就是(n-1)! % n. 题目里面n是10^9,不可能直接弄阶乘.这时可以想想,能不能找找规律看. 打表以后发现,如果是素数,答案

素数筛法—时间复杂度O(n)

请你想出一个算法求出n以内(含n)的所有素数,要求算法的时间复杂度越小越好. 这里介绍一种算法--快速线性素数筛法(欧拉筛法),时间复杂度O(n). 诀窍在于:筛除合数时,保证每个合数只会被它的最小质因数筛去.因此每个数只会被标记一次,所以算法时间复杂度为O(n). 具体请看下面的代码,主要函数是Prime(n). 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 vector<int> Prime(int n) { /