Author: lllyouo
Date: 20250822
tag: 差分
link:问题描述
对于长度为
分析
考察知识点:差分和多项式展开
对于一次操作
所以这次操作可以分解为:
- 给区间
的每个位置加上 - 给区间
的每个位置减去 - 给区间
的每个位置加上
使用三个差分数组:
d0:记录常数项的差分d1:记录一次项系数的差分d2:记录二次项系数的差分
对于操作
- 二次项部分:区间
加 (系数为 ) - 一次项部分:区间
加 (系数为 ) - 常数项部分:区间
加
最后通过积分还原原数组:
参考代码
cpp
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1000005, MOD = 998244353;
ll d0[N], d1[N], d2[N];
void add(int l, int r, ll val0, ll val1, ll val2) {
d0[l] = (d0[l] + val0) % MOD;
d0[r + 1] = (d0[r + 1] - val0 + MOD) % MOD;
d1[l] = (d1[l] + val1) % MOD;
d1[r + 1] = (d1[r + 1] - val1 + MOD) % MOD;
d2[l] = (d2[l] + val2) % MOD;
d2[r + 1] = (d2[r + 1] - val2 + MOD) % MOD;
}
int main() {
int n, m;
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i++) {
int L, R;
scanf("%d%d", &L, &R);
int len = R - L + 1;
ll c = L - 1; // c = L-1
// 分解为: i^2 - 2c*i + c^2
add(L, R, (c * c) % MOD, (-2 * c % MOD + MOD) % MOD, 1);
}
// 计算前缀和
for (int i = 1; i <= n; i++) {
d0[i] = (d0[i] + d0[i - 1]) % MOD;
d1[i] = (d1[i] + d1[i - 1]) % MOD;
d2[i] = (d2[i] + d2[i - 1]) % MOD;
}
// 计算最终结果: a_i = d2[i] * i^2 + d1[i] * i + d0[i]
for (int i = 1; i <= n; i++) {
ll t = (d2[i] * i % MOD * i % MOD + d1[i] * i % MOD + d0[i]) % MOD;
printf("%lld ", t);
}
return 0;
}