题意
给定一个区间
[
l
,
r
]
[l, r]
[l,r], 求区间中每一个数的k次方的正因子数的和。
正因子个数:比如12,有6个因子(1,2,3, 4, 6, 12)。
题解
- 有约数定理可知每一个数的正因子个数,但是分解因数的算法为 O ( N ) O(\sqrt{N}) O(N)。枚举区间中每个数的因子必定tle。所以需要另寻它解。
- 枚举 [ 1 ∼ r ] [1\sim \sqrt{r}] [1∼r]之间的质数,(若x不能被该区间中的质数整除,则x是含有比较大的质因子,需要特殊处理。1e12的区间,肯定会出现大素数)。
- 求出 [ l ∼ r ] [l \sim r] [l∼r]之间最小的一个素数 x 的倍数 j ,用while处理求得对应的 x 的指数(约数定理)。然后以x的长度对j增长。分别求出每一个 j 对应于 x 的指数。
- 若枚举结束后, [ l ∼ r ] [l \sim r] [l∼r]中的某个数仍然大于1,则肯定是含有比较大的因子,特殊处理即可。
- 该算法快就快在直接求质因子的指数,而不再需要像分解质因数一样需要循环查找。
收获小技巧
求第一个大于n的x的倍数的方法 : ( n + x − 1 ) / x ∗ x (n + x - 1) / x * x (n+x−1)/x∗x
代码
#include<cstdio>
#include<queue>
#include<set>
#include<cstdlib>
#include<string.h>
#include<string>
#include<iostream>
#include<cmath>
#include<unordered_map>
#include<map>
#include<algorithm>
#define endl "\n"
#define IOS ios::sync_with_stdio(0), cin.tie(0),cout.tie(0)
#define ft first
#define sd second
#define pll pair<ll, ll>
#define pii pair<int, int>
#define ll long long int
#define ull unsigned long long int
#define mt(a,b) memset(a, b, sizeof a)
//#define int long long
const double PI = acos(-1.0);
const int inf = 0x3f3f3f3f;
const int INF = 0x7fffffff;
const ll mod = 998244353;
using namespace std;
const int N = 1e5 + 7, M = 1e6 + 10;
ll tot, v[M], p[M];
ll val[M], d[M];
void primes()//埃氏筛
{
mt(v, 0);
int n = M;
for (int i = 2; i <= n; i++)
{
if (v[i]) continue;
p[++tot] = i;
for (int j = i; j <= n / i; j += i)
v[i * j] = 1;
}
}
int main()
{
IOS;
primes();//预处理求素数
int T; cin >> T;
while (T--)
{
ll l, r, k; cin >> l >> r >> k;
int num = lower_bound(p + 1, p + tot + 1, (int)sqrt(r)) - p;//小于sqrt(r)的素数个数
for (ll i = l; i <= r; i++)
val[i - l] = i, d[i - l] = 1;
for (int i = 1; i <= num; i++)
{
int x = p[i];
for (ll j = (l + x - 1) / x * x; j <= r; j += x)
{
int cnt = 0;
while (val[j - l] % x == 0) val[j - l] /= x, cnt++;//求质因子的指数(约数定理)
d[j - l] = (cnt * k + 1) % mod * d[j - l] % mod;
}
}
for (ll i = l; i <= r; i++)//对大因子特殊处理
if (val[i - l] > 1)
d[i - l] = d[i - l] * (k + 1) % mod;
ll ans = 0;
for (ll i = l; i <= r; i++)//求和得解
ans = (ans + d[i - l]) % mod;
cout << ans << endl;
}
return 0;
}