Counting Divisors
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 356 Accepted Submission(s): 105
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
解题思路:这是今天的多校题,比赛时没有做出来,看了题解才做出来。
我们知道一个数可以分解为很多质数的乘积,如下图:
然后我们肯定要把每个数进行素数分解,比赛时我也想到了这一点,但是这题的l, r到了1e12,然后比赛时对于大于1e6次方的素数(我们也不知道大于1e6的数是不是一个素数),进行素数判定,用的是米勒拉宾素数测试,然后一直t,看了题解之后才知道,根本不需要对大于1e6的数进行素数测试,我们可以用1 - 1e6之间的素数(这些可以用素数筛法处理出来),去筛大于1e6的数,举个简单的例子,比如现在我们有素数2,然后l, r中是2的倍数都不是素数,这样的话我们可以枚举1-1e6之间所有的素数(其实可以不用枚举所有,我们可以用二分处理出sqrt(r)左右的素数),去筛l, r之间的数,筛完之后剩下的就是素数,中间的值我们用几个数组记录下就行,最后加起来就是答案。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
const ll mod = 998244353;
ll l, r, k;
ll prime[maxn];
ll p2[maxn];//素数的平方,用于二分找出最小的s满足prime[s] * prime[s] >= r
ll ans[maxn];
int res;
bool valid[maxn];
ll result[maxn];
ll num[maxn];
bool visit[maxn];
void getPrime()
{
int tot = 0;
memset(valid, true, sizeof(valid));
for(ll i = 2; i < 1000000; i++)
{
if(valid[i])
{
++tot;
ans[tot] = i;
}
for(ll j = 1; ((j <= tot) && (i * ans[j] < 1000000)); j++)
{
valid[i * ans[j]] = false;
if(i % ans[j] == 0) break;
}
}
res = 0;
for(ll i = 2; i < 1000000; i++)
{
if(valid[i]) prime[++res] = i;
p2[res] = prime[res] * prime[res];
}
}
int main()
{
int T;
getPrime();//筛出1e6以内的素数
scanf("%d", &T);
while(T--)
{
scanf("%lld%lld%lld", &l, &r, &k);
memset(visit, false, sizeof(visit));
for(ll i = 1, j = l; j <= r; i++, j++)
{
num[i] = j;
result[i] = 1;
}
int L = 1;
int R = res;
int s = 1;
while(L <= R)
{
int mid = (L + R)>>1;
if(r >= p2[mid])
{
s = mid;
L = mid + 1;
}
else R = mid - 1;
}
s = res;
for(int i = 1; i <= s; i++)
{
ll pri = prime[i];
ll judge = l / pri;
int xx;
if(pri * judge == l)
{
xx = l;
}
else
{
xx = (judge + 1) * pri;
}
for(int j = xx - l + 1; j <= r - l + 1; j += pri)
{
ll yy = 0;
while(num[j] % pri == 0)
{
yy++;
num[j] /= pri;
}
if(yy)
{
result[j] = (result[j] * (k * yy%mod + 1)%mod)%mod;
visit[j] = true;
}
}
}
ll sum = 0;
for(int i = 1; i <= r - l + 1; i++)
{
if(!visit[i])
{
if(num[i] == 1) sum = (sum + 1) % mod;
else sum = (sum + k + 1) % mod;
}
else
{
if(num[i] == 1) sum = (sum + result[i]) % mod;
else sum = (sum + result[i] * (k + 1) % mod) % mod;
}
}
printf("%lld\n", sum);
}
return 0;
}