首页 > 其他分享 >P4786 [BalkanOI2018] Election 题解

P4786 [BalkanOI2018] Election 题解

时间:2023-12-19 12:11:37浏览次数:30  
标签:pre suf 后缀 前缀 P4786 题解 BalkanOI2018 int suf1

题意

给定一个长度为 \(n\) 的字符串 \(s\),有 \(m\) 个询问,每次询问最少需要删掉多少个字符才能使 \(l\) 到 \(r\) 组成的字符串当中的每一个前缀和后缀都满足 C 的数量不小于 T 的数量。

思路

因为要满足 C 的数量不小于 T 的数量,我们不妨设字符 C 的位置的值为 \(1\),字符 S 的位置的值为 -1。

考虑每一组询问 \(l\) 和 \(r\),设 \(pre_{i}\) 表示区间中 \(l\) 到 \(i\) 的和,\(suf_{i}\) 表示区间中 \(i\) 到 \(r\) 的和,即前缀和和后缀和。首先考虑暴力,可以先正序枚举一遍,取 \(pre\) 的最小值的相反数。并且在 \(pre\) 的每个分界点(值从 \(k\) 变成 \(k-1\) 并且 \(k-1\) 是之前最小的)标记一下表示删除,相当于是每当前缀和为 \(-1\) 的时候就删除当前数并且将前缀和变为 \(0\)。然后再倒序枚举一遍,之前删除过了的就不用管了,记修改后的后缀和为 \(suf1\),再取 \(suf1\) 中的最小值的相反数,最后把两个数加起来就可以了,时间复杂度 \(O(n^{2})\)。

贪心正确性证明:因为在前缀操作的时候删除的都是分界点,所以位置一定尽量靠后,这样删除后的后缀和一定比删除更靠前的数的后缀和更大,所以这样删除对于后缀也是最优的。

但是暴力的时间复杂度肯定是不优的,于是考虑优化。我们考虑操作前缀前的 \(suf_{i}\) 和操作前缀后的 \(suf1_{i}\) 有什么区别。其实相比于 \(suf\),\(suf1\) 加上了考虑前缀时在 \(i\) 到 \(r\) 中删除的点的数量,即:\(suf1_{i}=suf_{i}+(\min_{l \le j<i} pre_{j}-pre_{mn})\),那么后缀的最终的答案是 \(-suf1_{mn}\)。其中 \(pre_{mn}\) 和 \(suf1_{mn}\) 表示区间 \(l\) 到 \(r\) 中 \(pre\) 和 \(suf1\) 的最小值。

最后的答案是 \(ans=-(pre_{mn}+suf1_{mn})\),暴力表示为:

\(ans=-(pre_{mn}+\min(suf1_{l},\min(pre_{l})+suf_{l+1},\min(pre_{l},\dots,pre_{r-1})suf_{r})-pre_{mn})\)

化简得 \(ans=\min_{l\le i<j\le r}(pre_{i}+suf_{j})\)。

发现这个式子的意义为不相交的前缀和和后缀和的和的最小值,等价于区间和减去区间最大子段和。这两个东西用线段树维护即可,时间复杂度 \(O(n \log n)\)。

Code

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define inf 0x3f
#define inf_db 127
#define ls id << 1
#define rs id << 1 | 1
#define re register
#define endl '\n'
typedef pair <int,int> pii;
const int MAXN = 5e5 + 10;
int n,m,a[MAXN],op,l,r;
char c[MAXN];
struct SegmentTree{int l,r,sum,lmx,rmx,mx;}tree[MAXN << 2];
inline void Pushup(int id)
{
	tree[id].sum = tree[ls].sum + tree[rs].sum;
	tree[id].lmx = max(tree[ls].lmx,tree[ls].sum + tree[rs].lmx);
	tree[id].rmx = max(tree[rs].rmx,tree[rs].sum + tree[ls].rmx);
	tree[id].mx = max(max(tree[ls].mx,tree[rs].mx),tree[ls].rmx + tree[rs].lmx);
}
inline void Build(int id,int l,int r)
{
	tree[id].l = l,tree[id].r = r;
	if(l == r){tree[id].sum = tree[id].lmx = tree[id].rmx = a[l];tree[id].mx = max(0ll,a[l]);return;}
	int mid = (l + r) >> 1;
	Build(ls,l,mid),Build(rs,mid + 1,r);
	Pushup(id);
}
inline SegmentTree Query(int id,int l,int r,int a,int b)
{
	if(a <= l && b >= r) return tree[id];
	int mid = (l + r) >> 1;SegmentTree res;
	if(a > mid) return res = Query(rs,mid + 1,r,a,b);
	if(b <= mid) return res = Query(ls,l,mid,a,b);
	else
	{
		SegmentTree x = Query(ls,l,mid,a,b),y = Query(rs,mid + 1,r,a,b);
		res.sum = x.sum + y.sum;
		res.lmx = max(x.lmx,x.sum + y.lmx);
		res.rmx = max(y.rmx,y.sum + x.rmx);
		res.mx = max(max(x.mx,y.mx),x.rmx + y.lmx);
		return res;
	}
}
signed main()
{
	cin >> n >> (c + 1) >> m;
	for(int i = 1;i <= n;i++) a[i] = (c[i] == 'C' ? 1 : -1);
	Build(1,1,n);
	for(int i = 1;i <= m;i++)
	{
		cin >> l >> r;
		SegmentTree ans = Query(1,1,n,l,r);
		cout << ans.mx - ans.sum << endl;
	}
	return 0;
}

标签:pre,suf,后缀,前缀,P4786,题解,BalkanOI2018,int,suf1
From: https://www.cnblogs.com/Creeperl/p/17913422.html

相关文章

  • P8386 [PA2021] Od deski do deski 题解
    显然是一道计数dp。dp状态应该是最难的一部分了,个人认为这种状态设计得比较巧妙。如果像我刚开始一样设\(dp_{i,j}\)表示序列中一共有\(i\)个数,序列最后一个数为\(j\)的合法方案数的话,那么方程就会变得很不好转移,因为我们不知道当前的\(j\)和之前的某些数能不能匹配上,......
  • C0328 【1005 C组】模拟测试 斜率 题解
    原题链接:斜率。题意在一个平面直角坐标系中,给定\(n\)个点的横纵坐标,求出哪两个点所构成的连线的斜率最接近\(\frac{P}{Q}\)。数据范围:\(n\le1000000\)。思路显然这是一道数学题,不能直接暴力去找答案。首先我们可以弱化一下题目,求出斜率最接近\(y=0\)即\(x\)轴的两......
  • Omkar and Akmar 题解
    题意:有一个\(n\)个点的环,以及两个人。每个人可以向环中任意一个位置放置一个\(A\)或者\(B\),但是相邻的位置不能相同,不能行动者输。问最终的局面有多少种。一个结论是:后手必胜。证明:最终肯定不可能出现两个连续的空格,否则一定可以在其中一个上填\(A\)或\(B\)。所以最多只......
  • Square-free division (easy version) 题解
    题意:给定一个长度为\(n\)的序列,求最少能将这个序列分成多少段使得任意一段中不存在两个数的积为完全平方数。一个小Trick:如果两个数乘起来为平方数,可以先将每个数的平方因子除掉,然后这两个数必然相等。于是这道题被转化为了一个区间不能有相等的值,这就很典了。设\(pos_{a_{i......
  • Animals and Puzzle 题解
    原题链接:CF713D题意:给定一个\(n\timesm\)的地图\(a\),\(a_{i}\)为\(0\)或\(1\)。有\(t\)次询问,每次询问给定一个矩形,求出这个矩形中最大的由\(1\)构成的正方形的边长是多少。首先考虑预处理出\(d_{i,j}\)表示以\((i,j)\)为左上角的最大正方形边长是多少。对于每......
  • C0392 B 【1109 B组】预处理器 题解
    题意:求有多少个长度为\(n\)的数组\(a\)满足以下条件。条件一:\(l_{i}\lea_{i}\ler_{i}\)。条件二:\(a_{i}\)模\(2\)等于\(p_{i}\)。条件三:\(s\le\suma_{i}\let\)。求答案模\(mod\)的值,\(mod\)不一定是一个质数。数据范围:\(n\le13\)。又积累到一......
  • A Simple Task 题解
    这道题比较简单,简述一下思路。考虑状压\(DP\)。设\(dp_{i,j}\)表示走到第\(i\)个点,之前走过的点的状态为\(j\)的环的数量。这里有一个细节,就是我们都钦定每个走过的第一点是整个状态中编号最小的点,这样不会重复计算。考虑如何进行转移。如果当前点的编号比走过的最小编......
  • CF1900D Small GCD 题解
    原题链接:CF1900D,题意不多赘述。首先可以将\(a\)数组排序,并且枚举中间的那个数\(a_i\)。那么答案就是\(\sum_{j=1}^{i-1}\gcd(a_j,a_i)\times(n-i)\)。重点在于求前面的\(\gcd\)。可以用欧拉反演,但是也可以不用,因为我不会。假设我们当前已经枚举到了\(a_i\),设\(f_k\)表......
  • CF1902D Robot Queries 题解
    题意:有一个二维平面直角坐标系,给定一串向某个方向移动\(1\)个单位的操作。有\(q\)个询问,对于每个询问给定\(x,y,l,r\),问如果倒着做\(l\)到\(r\)这段区间中的操作,是否会经过\((x,y)\)。ds题。先预处理出\(sx_i,sy_i\)表示执行完操作\(i\)后的位置,如果在\([l,r]\)......
  • 华中师范大学2023新生赛 H 龙 题解
    Link华中师范大学2023新生赛H龙Question有\(m\)个宝石孔,有\(n\)个宝石,每个宝石可以提升\(a_i\)点战斗力每次镶嵌一个宝石,被选中的宝石会随机选择一个宝石孔进去,如果这个孔原来有宝石,则原来的宝石会被损坏你可以任意决定镶嵌宝石的顺序,她想知道,如果把着\(n\)颗宝......