前后缀分解
题型
给定一个数组(可以是高维度数组),若目标结果是求删掉数组中的一个元素后,剩余的全部元素进行运算的结果的最佳值,一般考虑前后缀分解。
若是求一个数组的子数组(子数组是指元素下标位置连续),也可以通过前后缀分解得到。任意一个子数组,都可以通过原数组减去一个前缀数组和一个后缀数组得到。
模板
for (int i = 1; i <= n; ++ i) {
pre[i] = pre[i] + pre[i - 1];
}
for (int i = n; i > 0; -- i) {
post[i] = post[i] + post[i + 1];
}
for (int i = 1; i <= n; ++ i) {
val = pre[i - 1] + post[i + 1];//结构体可以重载+运算符
//对val值进行计算
}
例题
例题一:Maximal intersection
题目链接:https://codeforces.com/problemset/problem/1029/C
题目

题解
要求的结果就是扣去一个区间后剩余的全部区间的交集。因此,符合前后缀分解的使用场景。
求一次前缀区间交集与一次后缀区间交集,遍历一遍求前缀与后缀的交集的大小的最大值即可。
参考代码
C++
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
int n, ans;
struct seg {
int l, r;
seg operator + (const seg& s) {
seg _s;
_s.l = max(this -> l, s.l);
_s.r = min(this -> r, s.r);
return _s;
}
};
int main() {
IOS
cin >> n;
vector<seg> pre(n + 2), post(n + 2);
pre[0].l = post[0].l = pre[n + 1].l = post[n + 1].l = 0;
pre[0].r = pre[n + 1].r = post[0].r = post[n + 1].r = 1e9;
for (int i = 1; i <= n; ++ i) {
cin >> pre[i].l >> pre[i].r;
post[i] = pre[i];
}
for (int i = 1; i <= n; ++ i) {
pre[i] = pre[i] + pre[i - 1];
}
for (int i = n; i > 0; -- i) {
post[i] = post[i] + post[i + 1];
}
for (int i = 1; i <= n; ++ i) {
pre[i - 1] = pre[i - 1] + post[i + 1];
ans = max(ans, pre[i - 1].r - pre[i - 1].l);
}
cout << ans << '\n';
return 0;
}
例题二:Maximal intersection扩展题
题目
如果去掉一个区间 求的是剩下的全部区间的两两交集之和 最大能是多少?
题解
利用差分数组与前缀和实现,但由于数据范围大,数据量小,要么考虑离散化,要么考虑使用map去模拟差分,再结合前后缀分解,即可实现去掉一个区间,求剩下的全部区间的两两交集之和的最大值
例题三:不为 X 的倍数的最长子数组长度
题目链接:https://codeforces.com/problemset/problem/1364/A
参考代码:
C++
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr int N = 1e5 + 7;
int T, n, x;
int a[N];
ll pre[N], pst[N];
void solve() {
cin >> n >> x;
for (int i = 1; i <= n; ++ i) cin >> a[i];
if (x == 1) {
cout << -1 << '\n';
return ;
}
int res = -1, last = -1;
for (int i = 1; i <= n; ++ i) pre[i] = pre[i - 1] + a[i];
ll sum = pre[n];
if (sum % x) {
cout << n << '\n';
return ;
}
pst[n + 1] = 0;
for (int i = n; i >= 1; -- i) {
pst[i] = pst[i + 1] + a[i];
if (pst[i] % x) {
if (last == -1) last = i;
res = n - i + 1;
}
}
if (last != -1) {
int num = n - last + 1;
for (int i = 1; i <= n; ++ i) {
if (pre[i] % x) res = max(res, i);
else if (last > i) res = max(res, n - num);
ll s = sum - pre[i];
if (s % x) res = max(n - i, res);
else if (last > i) res = max(res, n - i - num);
}
}
cout << res << '\n';
}
int main() {
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
cin >> T;
while (T --) {
solve();
}
return 0;
}
浙公网安备 33010602011771号