1.题目链接。问题很简洁,就是求一下区间[l,r]里的每一个i,i的k次方因子个数之和。
首先我们知道d(i)=(a1+1)*(a2+1)...(ak+1),其中a1,a2...ak是对i进行素因子分解之后每个素因子的指数。这个结论很好证明,就简单的排列组合一下就好。那么对于:i^k.唯一的变化就是素因子分解之后ai变成了ai*k.那么式子形式还是不变的:d(i^k)=(a1*k+1)...(ak*k+1).式子推出来了,然后事情并没有完成。因为数据很大,但是区间不大,所以我们直接筛整个区间的素数,然后分解素因子。做这个操作之前我们首先需要把预处理前1e6之内的素数,然后使用这些素数进行分解区间的每一个数据。最后统计答案即可。这里有一种离散化的思想,我们可定是需要记录[l,r]整个区间的数据的,但是我们没有办法直接记录,所以就做一个相对的变换,所有数的位置相对与l来计算。这样1e6的数组存下它就完事了,然后统计这个数组种每个元素的贡献,先把他们分解,计算每个数据的贡献,最后统计。但是在最后统计的时候需要注意,判断是不是分解完了,如果数据剩余的是1,那么表示刚好分解完,如果不是1,说明还剩下一个因子,把它也要计算上去。完美!
using namespace std;
const int MAXN = 1e6 + 10;
const int mod = 998244353;
int prime[MAXN], vis[MAXN], tot;
ll sum[MAXN], gel[MAXN];
void get_prime()
{
for (int i = 2; i < MAXN; i++)
{
if (!vis[i])
{
prime[tot++] = i;
for (int j = 2; j*i < MAXN; j++)
{
vis[i*j] = 1;
}
}
}
}
int main()
{
get_prime();
ll l, r;
int t, k;
scanf("%d", &t);
while (t--)
{
scanf("%lld%lld%d", &l, &r, &k);
for (int i = 0; i <= r - l; i++)
{
sum[i] = 1;
gel[i] = i + l;
}
for (int i = 0; i < tot; i++)
{
ll a = (l + prime[i] - 1) / prime[i] * prime[i];
for (ll j = a; j <= r; j+=prime[i])
{
ll cnt = 0;
while (gel[j - l] % prime[i] == 0)
{
cnt++;
gel[j - l] /= prime[i];
}
sum[j - l] = sum[j - l] * (cnt*k + 1 % mod);
sum[j - l] %= mod;
}
}
ll ans = 0;
for (int i = 0; i <= r - l; i++)
{
if (gel[i] != 1)
sum[i] = sum[i] * (k + 1);
ans += sum[i];
ans %= mod;
}
cout << ans << endl;
}
}