1 条题解
-
0
由题意可知这是一道区间修改,最后区间查询的问题。因为只有一次查询,所以我们可以不上线段树或者树状数组,直接用数组做。
思考这个问题:对每个区间里的数依次加 ,可以类比到我们学差分的时候是对每个数加 。二者是否有相同点。
首先看普通的差分:将 这个区间的每个数加
差分一次得:
我们可以看到对差分数组 的影响就是 ,两次操作
那么对于每次加的数不是 呢
多次差分:
$$0,1,3,5,7,-16,0,0,0,\cdots\\ 0,1,2,2,2,-23,16,0,0,\cdots\\ 0,1,1,0,0,-25,39,-16,0,\cdots $$我们看到做了三次差分后,变得好像有规律了,影响了 这五个地方的值。所以我们每次加的操作可以等价操作这 个位置的值。
那么我们来看看每个位置有什么方法可以快速计算出影响。
这两个是可以一眼看出的,剩下的三个我们推导一下,我们记区间长度为():
在 位置,相当于减去了
在 位置,相当于加上了
在 位置,相当于减去了
所以我们每次就修改这 个位置,最后 次前缀和就可以复原数组了,然后在一次前缀和计算数组的和。注意取模计算减法!!!
参考代码:
#include <bits/stdc++.h> using u32 = unsigned; using i64 = long long; using u64 = unsigned long long; using u128 = unsigned __int128; constexpr int mod = 998244353, N = 200010; std::vector<i64> a(N); void getsum(int n) { for (int i = 1; i <= n; i++) { a[i] = (a[i] + a[i - 1]) % mod; } } int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int n, m; std::cin >> n >> m; while (m--) { int l, r; std::cin >> l >> r; a[l]++; a[l + 1]++; a[r + 1] = (a[r + 1] % mod + mod - ((i64)(r - l + 1) * (r - l + 1) % mod + 2LL * (r - l) % mod + 3) % mod) % mod; a[r + 2] = (a[r + 2] % mod + 2 * (i64)(r - l + 1) * (r - l + 1) % mod + 2LL * (r - l) % mod + 1) % mod; a[r + 3] = (a[r + 3] % mod + mod - ((i64)(r - l + 1) * (r - l + 1) % mod)) % mod; } getsum(n); getsum(n); getsum(n); getsum(n); std::cout << a[n] % mod << "\n"; return 0; }
方法二:将区间修改改为单点修改。
其实我们可以直接将这个区间里需要增加的值直接计算出来,通过平方和公式:
这样我们可以直接将增加的值直接加到 的位置,在 的位置减去。只需要执行 次操作,然后前缀和一次还原。
注意:在取模运算做除法运算时,需要将除法变为乘法,即乘以这个数在 mod 下的乘法逆元。
参考代码:
#include <bits/stdc++.h> using u32 = unsigned; using i64 = long long; using u64 = unsigned long long; using u128 = unsigned __int128; constexpr int mod = 998244353, N = 200010; std::vector<i64> a(N); i64 power(i64 a, i64 b) { i64 res = 1; while (b) { if (b & 1) res = res * a % mod; a = a * a % mod; b >>= 1; } return res; } i64 inv(i64 x) { return power(x, mod - 2); } void getsum(int n) { for (int i = 1; i <= n; i++) { a[i] = (a[i] + a[i - 1]) % mod; } } int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int n, m; std::cin >> n >> m; while (m--) { int l, r; std::cin >> l >> r; i64 len = r - l + 1; i64 add = (len * (len + 1) % mod * (len * 2 + 1) % mod * inv(6)) % mod; a[r] = (a[r] + add) % mod; a[r + 1] = (a[r + 1] % mod + mod - add) % mod; } getsum(n); getsum(n); std::cout << a[n] % mod << "\n"; return 0; }
信息
- ID
- 154
- 时间
- 2000ms
- 内存
- 256MiB
- 难度
- 8
- 标签
- 递交数
- 25
- 已通过
- 6
- 上传者