AB5000的算法

没有什么技术含量的吧..

只需要暴力预处理50005000以内的逆元,然后直接暴力计算答案,记录一个前缀和就可以O(1)O(1)完成询问了.

T = 1T=1的算法

首先一个询问求的东西就是这个:\sum_{i=A}^{B}\sum_{j=1}^{i}\lbrace\frac{i}{j}\rbrace \qquad (\bmod\ 998244353)i=ABj=1i{ji}(mod 998244353)

然后我们可以把它变个形:

\sum_{i=A}^{B}\sum_{j=1}^{i}(\frac{i}{j}-\lfloor\frac{i}{j}\rfloor)\qquad(\bmod\ 998244353)i=ABj=1i(jiji)(mod 998244353)

\sum_{i=A}^{B}\sum_{j=1}^{i}\frac{i}{j}-\sum_{i=A}^{B}\sum_{j=1}^{i}\lfloor\frac{i}{j}\rfloor\qquad(\bmod\ 998244353)i=ABj=1ijii=ABj=1iji(mod 998244353)

\sum_{i=1}^{B}\sum_{j=max(A,i)}^{B}\frac{j}{i}-\sum_{i=1}^{B}\sum_{j=A}^{B}\lfloor\frac{j}{i}\rfloor\qquad(\bmod\ 998244353)i=1Bj=max(A,i)Biji=1Bj=ABij(mod 998244353)

\sum_{i=1}^{B}\sum_{j=max(A,i)}^{B}\frac{j}{i}-\sum_{i=1}^{B}(\sum_{j=0}^{B}\lfloor \frac{j}{i} \rfloor-\sum_{j=0}^{A-1}\lfloor \frac{j}{i} \rfloor)\qquad(\bmod\ 998244353)i=1Bj=max(A,i)Biji=1B(j=0Bijj=0A1ij)(mod 998244353)

然后我们只需要分别求出左右两边的值就好了.

前面一半我们只需要枚举ii,然后里面的jj可以用高斯求和公式直接算出来,然后乘上一个ii的逆元就好.

后面一半的话..

我们先拿i=3的情况玩玩:

0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5...

发现了什么??

如果不太明白,再多拿一些数搞一搞,你就会发现这个规律了..

然后后面的一样只需要枚举ii,后面的东西也可以用高斯求和公式算.

这样就有50分了.

75分算法

把前面两个拼起来就好了.

100分算法

首先我们还是用T=1T=1的思路,把这个式子拆成这个样子:

\sum_{i=A}^{B}\sum_{j=1}^{i}\frac{i}{j}-\sum_{i=A}^{B}\sum_{j=1}^{i}\lfloor\frac{i}{j}\rfloor\qquad(\bmod\ 998244353)i=ABj=1ijii=ABj=1iji(mod 998244353)有没有可以直接预处理的办法呢??

答案当然是有的..

对于前一个式子,我们只需要预处理11~BB的逆元,然后求一个前缀和,我们发现ii的每一次增加,实际上就是加上11~i-1i1的逆元+11(\frac{i}{i}ii).这里可以好好思考一下.

所以我们只需要用线性求逆元的方法,求一遍前缀和后计算每一个ii的里面的\sum^i_{j=1}\frac{i}{j}j=1iji的值,然后再求一遍前缀和我们就可以O(1)O(1)求得前面一块的任意一对A,B的值了.

然后再考虑后面一块.

首先我们可以考虑\lfloor\frac{i}{j}\rfloorji⌋的更多的含义.

这个等同于求出小于等于ii的数中有多少个数是jj的倍数.

然后拓展到\sum_{j=1}^{i}\lfloor\frac{i}{j}\rfloorj=1iji⌋呢?

这个就是求小于等于ii的数中有多少是11的倍数,22的倍数,33的倍数...ii的倍数.

也就是说,对于每一个数,它对这个答案就有它的因子个数个贡献.

所以我们就可以得到这样一个等式:

\sum_{j=1}^{i}\lfloor\frac{i}{j}\rfloor=\sum_{j=1}^{i}d(i)j=1iji=j=1id(i)

其中d(i)d(i)表示ii的因子个数.

然后考虑如何快速求11~nn的因子个数.

这个就是积性函数了..可以使用欧拉线行筛

求出d(i)d(i)之后,我们就只需要求两次前缀和就好了..这个可以直接把上面的等式代入原式就可以看出来了..

这样子这道题就解决了..

代码如下(请原谅蒟蒻丑陋的码风):

#include <bits/stdc++.h>

using namespace std;

#define reg register

typedef long long ll;

inline int read() {
    reg int s = 0; reg bool t = 0; reg char ch = getchar();
    while(!isdigit(ch)) t |= ch == '-', ch = getchar();
    while(isdigit(ch)) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
    return t ? -s : s;
}

const char FI[] = "dinner.in";
const char FO[] = "dinner.out";
const int N = 1000000;
const int mod = 998244353;

int T;
int A;
int B;
int d[N + 1];
int s[N + 1];
int f[N + 1];
int ins[N + 1] = {0, 1};

int tot;
int prime[N + 1];
bitset<N + 1>Check;

void init() {
    d[1] = 1;
    for(reg int i = 2, tmp = 2; i <= N; i++, tmp = i) {
        if(!Check[i]) prime[++tot] = i, d[i] = 2;
        for(reg int j = 1, pr = prime[j], s = 2; j <= tot && i * pr <= N; pr = prime[++j]) {
            Check[i * pr] = 1;
            if(i % pr == 0) {
                while(tmp % pr == 0) tmp /= pr, s++;
                d[i * pr] = d[tmp] * s;
                break;
            }
            d[i * pr] = d[i] << 1;
        }
    }
    for(reg int i = 1; i <= N; i++) s[i] = s[i - 1] + d[i], s[i] -= s[i] >= mod ? mod : 0;
    for(reg int i = 1; i <= N; i++) s[i] += s[i - 1], s[i] -= s[i] >= mod ? mod : 0;
    for(reg int i = 2; i <= N; i++) ins[i] = 1LL * (mod - mod / i) * ins[mod % i] % mod;
    for(reg int i = 2; i <= N; i++) ins[i] += ins[i - 1], ins[i] -= ins[i] >= mod ? mod : 0;
    for(reg int i = 1; i <= N; i++) f[i] = f[i - 1] + ins[i - 1] + 1, f[i] -= f[i] >= mod ? mod : 0;
    for(reg int i = 1; i <= N; i++) f[i] += f[i - 1], f[i] -= f[i] >= mod ? mod : 0;
}

int main() {
    init();
    reg int T = read();
    for(reg int Q_Q = 0; Q_Q < T; Q_Q++) {
        A = read() - 1, B = read(),
        printf("%d\n", ((f[B] - f[A] - s[B] + s[A]) % mod + mod) % mod);
    }
    return 0;
}