Problem
定义 d(n)
表示数字 n 的约数个数
给定 l, r, k, 求 (∑ri=ld(ik))mod998244353
Limit
1≤l≤r≤1012
1≤k≤107
Idea
n=ap11⋅ap22⋯apii (其中 ai 均为质数)
根据组合原理求 n 的约数个数 : d(n)=(p1+1)(p2+1)⋯(pi+1)
由于 l 与 r 最大
1012
,故预处理出 [1, 1e6]
的所有质数。则 [l, r]
中每个数最多只有一个比 1e6
大的质数。(若存在两个及以上的大于 1e6
的质数,则乘积必然大于
1012
。
枚举 [1, 1e6]
的每个质数,对于每个质数 prime 枚举区间 [l, r]
的巧合为 prime 整数倍的数 number ,循环处理 number 有多少个 prime 因子存在。假设为 cnt 个,则该
numberk
含有
cnt×k
个质数,对
d(number)
贡献为
×(cnt×k+1)
。
对 [l, r]
的 d(number) 求和。
应注意可能含有一个比 1e6
的质数,此处因进行处理。
Code
#include<bits/stdc++.h>
using namespace std;
const int mod = 998244353;
const int N = 1000000 + 10;
bool isprime[N];
int primes[N/3], tot, T, k;
long long divs[N], l, r, arr[N];
void getPrime() {
tot = 0;
memset(isprime, 0, sizeof(isprime));
for(int i=2, j;i<N;i++) {
if(!isprime[i]) primes[tot++] = i;
for(j=0;j<tot && i*primes[j] < N;++j) {
isprime[i*primes[j]] = true;
if(i % primes[j] == 0) break;
}
}
}
int main()
{
getPrime();
scanf("%d", &T);
while(T-- && scanf("%lld %lld %d", &l, &r, &k)!=EOF)
{
for(long long i=l;i<=r;i++)
{
arr[i-l] = i;
divs[i-l] = 1;
}
for(int i=0;i<tot;i++)
{
long long start = l/primes[i]*primes[i] + (l%primes[i]?primes[i]:0);
for(long long j=start, cnt;j<=r;j+=primes[i])
{
cnt = 0;
while(arr[j-l] % primes[i] == 0) {
cnt++;
arr[j-l] /= primes[i];
}
(divs[j-l] *= (cnt * k + 1ll)) %= mod;
}
}
long long ans = 0;
for(long long i=l;i<=r;i++)
{
if(arr[i-l] != 1) (divs[i-l] *= (k+1ll)) %= mod;
(ans += divs[i-l]) %= mod;
}
printf("%lld\n", ans);
}
}