• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

RomanLin

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

前后缀分解

题型

给定一个数组(可以是高维度数组),若目标结果是求删掉数组中的一个元素后,剩余的全部元素进行运算的结果的最佳值,一般考虑前后缀分解。

若是求一个数组的子数组(子数组是指元素下标位置连续),也可以通过前后缀分解得到。任意一个子数组,都可以通过原数组减去一个前缀数组和一个后缀数组得到。

模板

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;
}

posted on 2024-05-01 20:12  RomanLin  阅读(132)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3