首页 > 其他分享 >QOJ5013 Astral Birth(凸包,分治,堆,贪心)

QOJ5013 Astral Birth(凸包,分治,堆,贪心)

时间:2023-02-10 19:45:46浏览次数:70  
标签:cur QOJ5013 rs int len 凸包 ls Birth ns

QOJ5013 Astral Birth

\(m = 1\) 直接求 LIS。

否则对于 \(m \ge 2\),就是求把序列分成 \(m + 1\) 段,每段翻转或者不翻转,最终最多 \(1\) 的个数。

很明显相邻两段翻不翻转的选择是互异的。

做法 1:容易发现最多的 \(1\) 个数和段数的关系是个凸包,所以可以分治合并凸包 DP。

做法 2:刚开始先按初始颜色分段。枚举最左、最右的段的选择(\(4\) 种),如果和当前不同就把当前端点段翻转和相邻段合并。贪心,每次选择不是端点段的最短的段 \(x\),和两边的段 \(y, z\) 合并(段数 \(-2\)),变成颜色和两边一样,长度为 \(y + z - x\) 的段。可以用堆或桶维护,时间复杂度最低 \(\Theta(n)\)。

错因:没有对左右端的选择分类,而是选择强行处理细节。

代码

#include <bits/stdc++.h>
using namespace std;

template<typename A>
string to_string(A v) {
	bool first = true;
	string res = "{";
	for (const auto& x : v) {
		if (!first) res += ", ";
		first = false;
		res += to_string(x);
	}
	res += "}";
	return res;
}

void debug_out() { cerr << "\n"; }

template<typename U, typename... T>
void debug_out(const U& x, const T&... args) {
	cerr << " " << to_string(x);
	debug_out(args...);
}

#define debug(...) cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__) // debugrs

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	int n;
	string s;
	cin >> n >> s;
	vector<int> sum(n + 1, 0);
	for (int i = 0; i < n; ++i) sum[i + 1] = sum[i] + (s[i] == '1');
	vector<int> f(n + 1, 0);
	for (int i = 0; i <= n; ++i) f[1] = max(f[1], (i - sum[i]) + (sum[n] - sum[i]));
	vector<int> S;
	for (int L = 0, r; L < n; L = r) {
		r = L + 1;
		while (r < n and s[r] == s[L]) ++r;
		S.emplace_back(r - L);
	}
	int ns = S.size();
	fill(f.begin() + max(2, ns - 1), f.end(), n);
	if (ns >= 4) for (int X : {0, 1}) for (int Y : {0, 1}) {
		vector<int> ls(ns + 1), rs(ns + 1), len(ns), del(ns, false);
		auto delet = [&](int i) {
			rs[ls[i]] = rs[i];
			ls[rs[i]] = ls[i];
			del[i] = true;
		};
		vector<vector<int>> V(n + 1);
		for (int i = 0; i < ns; ++i) {
			ls[i] = i == 0 ? ns : i - 1;
			rs[i] = i == ns - 1 ? ns : i + 1;
			len[i] = S[i];
		}
		ls[ns] = ns - 1;
		rs[ns] = 0;
		int k = ns, cur = n;
		if (s[0] - '0' != X) {
			k -= 1;
			cur -= S[0];
			delet(0);
		}
		if (s[n - 1] - '0' != Y) {
			k -= 1;
			cur -= S[ns - 1];
			delet(ns - 1);
		}
		if (k >= 3) f[k - 1] = max(f[k - 1], cur);
		for (int i = 0; i < ns; ++i) if (ls[i] != ns and rs[i] != ns) V[len[i]].push_back(i);
		for (int L = 1; L <= n and k >= 4; ++L) while (V[L].size() and k >= 4) {
			int i = V[L].back();
			V[L].pop_back();
			if (del[i]) continue;
			// debug(L, i);
			cur -= L;
			len[i] = len[ls[i]] + len[rs[i]] - len[i];
			delet(ls[i]);
			delet(rs[i]);
			if (k >= 4) f[k - 2] = max(f[k - 2], cur);
			if (k >= 5) f[k - 3] = max(f[k - 3], cur);
			k -= 2;
			if (ls[i] != ns and rs[i] != ns) V[len[i]].push_back(i);
		}
	}
	for (int i = 1; i <= n; ++i) cout << f[i] << ' ';
	cout << '\n';
}

标签:cur,QOJ5013,rs,int,len,凸包,ls,Birth,ns
From: https://www.cnblogs.com/Pizza1123/p/17110137.html

相关文章

  • 二维凸包
    Andrew算法时间复杂度\(O(nlogn)\)把所有点以横坐标为第一关键字排序,纵坐标为第二关键字最小的元素和最大的元素一定在凸包上从第一个点开始遍历,如果下一个点在栈顶的......
  • 【CCCC】L3-009 长城 (30分),计算几何+凸包,极角排序
    problemL3-009长城(30分)正如我们所知,中国古代长城的建造是为了抵御外敌入侵。在长城上,建造了许多烽火台。每个烽火台都监视着一个特定的地区范围。一旦某个地区有外敌入......
  • 20230129 T1 生日蛋糕(birth)
    生日蛋糕(birth)伤心题。。。题意\(n\)个点的树,第\(i\)个点有点权\(1\lea_i\lem\)。对于每个\(i\)满足\(1\lei\lem\),求出连通块内点权最大值为\(i\)的个......
  • 【YBT2023寒假Day3 C】樱桃莓莓(凸包)(线段树)
    樱桃莓莓题目链接:YBT2023寒假Day3C题目大意给你一棵有根数,点有a,b两种权值。然后一个点的分数是它以及它所有祖先的a权值和的绝对值乘上b权值和的绝对值。然后......
  • 【计算几何】浅谈凸包Andrew算法
    前置知识基础计算几何定义。引文这样一个问题,有许多个杆子,需要用绳子围住所有的杆子,然鹅没有很多的绳子,求最短需要多少绳子。整个图大概是这样的,正文我们要如何解......
  • 十九(一) - The Rebirth of Hygebra
    十九(一)-TheRebirthofHygebra今天打了一下午带一晚上游戏,现在是2022年11月13日午夜之后20分钟,十九年前的现在我正即将诞生。我在一片头晕沉沉中梳理心情,正如Hygebra......
  • 【学习笔记】分块凸包
    啊啊啊啊我不会凸包啊啊啊啊啊啊凸包怎么学啊啊啊啊啊啊啊啊啊(已黑化好像很套路,用于解决一类区间加一段等差数列,求最大/最小值的问题。P4192旅行规划简单的题意转化,可......
  • Birthday Attack
    BirthdayAttackQ&A1Q:Howmanypeoplemustbethereinaroomtomaketheprobability100%thatat-leasttwopeopleintheroomhavesamebirthday?A:367(s......
  • 2935. 信用卡凸包
    题目链接2935.信用卡凸包信用卡是一个矩形,唯四个角作了圆滑处理,使它们都是与矩形的两边相切的\(\frac{1}{4}\)圆,如下图所示。现在平面上有一些规格相同的信用卡,试求......
  • 矢量&凸包学习笔记
    矢量&凸包学习笔记矢量矢量(向量)的定义和表示法定义:一条有方向的线段。表示:如下图。那么我们把这一条矢量写作:\(\overrightarrow{AB}\),它的长度为\(a\),记作\(\left|\o......