方案一 \(O(n\sqrt
n)\) :
首先可以考虑一下这个小数部分该如何处理,显然是可以利用这个高斯函数的性质的:\(\{p\}=p-[p]\) 。
所以第 \(n\) 行的和就可以写作:
\[
\begin{aligned}
sum_n&=\sum_{i=1}^n\frac {n\mod i}i\\
&=\sum_{i=1}^n\frac ni-\sum i\times[\frac ni]\\
\end{aligned}
\] 所以后面那个可以整数分块,前面的 \(O(n)\) 预处理,整体时间复杂度 \(O(n\sqrt n)\) ,过不了的。
期望得分:\(50\) 分
方案二 \(O(n\log
n)\)
考虑这一行的分子理论上应该是上一行的分子 \(+1\) ,所以理论上是可以直接继承的,但是分子的值域却只能是
\([0,n)\) ,所以要考虑剪去变成零的数的贡献,那么这个就应该是
\(\sigma(i)\) ,就可以 \(O(n\log n)\) 预处理了。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 #include <bits/stdc++.h> using namespace std;typedef long long ll;const int mod = 998244353 ;const int maxn = 1e6 + 10 ;const char infile[] = ".in" ;const char outfile[] = ".out" ;inline int read () { int x (0 ) , t (0 ) ; char o (getchar()) ; while (o < '0' || o > '9' ) { if (o == '-' ) t = 1 ; o = getchar (); } for (; o >= '0' && o <= '9' ; o = getchar ()) x = (x << 1 ) + (x << 3 ) + (o ^ 48 ); return t ? -x : x; } inline void file () { freopen (infile, "r" , stdin); freopen (outfile, "w" , stdout); } int f[maxn], cnt[maxn], inv[maxn];inline void init () { inv[1 ] = 1 ; for (int i = 2 ; i < maxn; ++i) inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod; for (int i = 3 ; i < maxn; ++i) inv[i] = (inv[i] + inv[i - 1 ]) % mod; for (int i = 2 ; i < maxn; ++i) for (int j = i << 1 ; j < maxn; j += i) cnt[j]++; for (int i = 3 ; i < maxn; ++i) { ll temp = ((f[i - 1 ] - f[i - 2 ]) % mod + mod) % mod + inv[i - 1 ]; f[i] = (temp - cnt[i] + f[i - 1 ] + mod) % mod; } } int main () { init (); int t = read (); while (t--) { int a = read (), b = read (); printf ("%d\n" , (f[b] - f[a - 1 ] + mod) % mod); } }
方案三 \(O(n)\)
事实证明确实是可以 \(O(n)\)
的,就是一个线性筛就可以了。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 #include <bits/stdc++.h> using namespace std;typedef long long ll;const int mod = 998244353 ;const int maxn = 1e6 + 10 ;const char infile[] = ".in" ;const char outfile[] = ".out" ;inline int read () { int x (0 ) , t (0 ) ; char o (getchar()) ; while (o < '0' || o > '9' ) { if (o == '-' ) t = 1 ; o = getchar (); } for (; o >= '0' && o <= '9' ; o = getchar ()) x = (x << 1 ) + (x << 3 ) + (o ^ 48 ); return t ? -x : x; } inline void file () { freopen (infile, "r" , stdin); freopen (outfile, "w" , stdout); } int f[maxn], cnt[maxn], inv[maxn], sum[maxn];int p[maxn], idx[maxn], tot;bool vis[maxn];inline void init () { inv[1 ] = 1 ; for (int i = 2 ; i < maxn; ++i) { inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod; sum[i] = (sum[i - 1 ] + inv[i]) % mod; if (!vis[i]) p[++tot] = i, idx[i] = 1 , cnt[i] = 2 ; for (int j = 1 ; j <= tot && i * p[j] < maxn; ++j) { vis[i * p[j]] = 1 ; if (i % p[j] == 0 ) { cnt[i * p[j]] = cnt[i] / (idx[i] + 1 ) * (idx[i] + 2 ); idx[i * p[j]] = idx[i] + 1 ; break ; } cnt[i * p[j]] = cnt[i] << 1 ; idx[i * p[j]] = 1 ; } if (i == 2 ) continue ; ll tmp = ((f[i - 1 ] - f[i - 2 ]) % mod + mod) % mod + sum[i - 1 ]; f[i] = (tmp - (cnt[i] - 2 ) + f[i - 1 ] + mod) % mod; } } int main () { init (); int t = read (); while (t--) { int a = read (), b = read (); printf ("%d\n" , (f[b] - f[a - 1 ] + mod) % mod); } }