首页 > 其他分享 >CodeForces 1876D Lexichromatography

CodeForces 1876D Lexichromatography

时间:2023-10-09 10:36:43浏览次数:59  
标签:typedef int CodeForces long fa Lexichromatography maxn 1876D define

洛谷传送门

CF 传送门

这说明你的能力还不足以维持 IM。

显然 balanced 的充要条件是,对于每个值,染色一定是 RB 交替。然后一种值只会有先染红或先染蓝两种情况。

然后还剩下字典序严格小于的条件。我场上的想法是枚举 \(\text{LCP}\),然后推出来一个巨大麻烦做法,根本写不出来。

但是实际上字典序严格小于就是诈骗。考虑遇到第一个红蓝组成的子序列不等的值,此时我们存在唯一一种是否交换这两种颜色的方案,使得红子序列字典序严格小于(或大于)蓝子序列。

所以,如果设 \(a\) 为红小于蓝的方案数,\(b\) 为红大于蓝的方案数,\(c\) 为红等于蓝的方案数(这里均指字典序),\(k\) 为序列中出现的不同的值的个数,那么有 \(a = b, a + b + c = 2^k\),所以 \(a = b = \frac{2^k - c}{2}\)。问题来到如何求 \(c\)。

既然红等于蓝,那么如果有一种值出现奇数次就寄了。

然后我们考虑把每种值第奇数次出现和第偶数次出现的位置连起来,这样组成了若干条线段,并且线段的左端点和右端点染的颜色一定不同。

若线段存在包含关系,那么一定不能做到字典序相等。

否则,对于一对相交的线段,一定是形如 \(l_1 < l_2 < r_1 < r_2\) 的形式,那么由字典序相等的限制,可知此时 \(l_2\) 位置的颜色和 \(l_1\) 位置的颜色相等。那么最后我们会得到若干个等价类,设等价类的个数为 \(d\),那么 \(c = 2^d\)。

时间复杂度 \(O(n \log n)\)。

code
// Problem: D. Lexichromatography
// Contest: Codeforces - Codeforces Round 902 (Div. 1, based on COMPFEST 15 - Final Round)
// URL: https://codeforces.com/contest/1876/problem/D
// Memory Limit: 512 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 200100;
const ll mod = 998244353;

ll n, a[maxn], pw[maxn], fa[maxn];
vector<int> vc[maxn];

int find(int x) {
	return fa[x] == x ? x : fa[x] = find(fa[x]);
}

inline bool merge(int x, int y) {
	x = find(x);
	y = find(y);
	if (x != y) {
		fa[x] = y;
		return 1;
	} else {
		return 0;
	}
}

void solve() {
	scanf("%lld", &n);
	ll N = 0;
	pw[0] = 1;
	for (int i = 1; i <= n; ++i) {
		scanf("%lld", &a[i]);
		N = max(N, a[i]);
		vc[a[i]].pb(i);
		pw[i] = pw[i - 1] * 2 % mod;
	}
	int cnt = 0;
	for (int i = 1; i <= N; ++i) {
		fa[i] = i;
		if (vc[i].size()) {
			++cnt;
		}
	}
	for (int i = 1; i <= N; ++i) {
		if (vc[i].size() & 1) {
			printf("%lld\n", pw[cnt - 1]);
			return;
		}
	}
	vector<pii> S;
	for (int i = 1; i <= N; ++i) {
		for (int j = 0; j < (int)vc[i].size(); j += 2) {
			S.pb(vc[i][j], vc[i][j + 1]);
		}
	}
	sort(S.begin(), S.end());
	for (int i = 1; i < (int)S.size(); ++i) {
		if (S[i].scd < S[i - 1].scd) {
			printf("%lld\n", pw[cnt - 1]);
			return;
		}
	}
	int lst = 0, t = cnt;
	for (pii p : S) {
		int l = p.fst, r = p.scd;
		if (l < lst) {
			if (merge(a[l], a[lst])) {
				--t;
			}
		}
		lst = r;
	}
	printf("%lld\n", (pw[cnt - 1] - pw[t - 1] + mod) % mod);
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

标签:typedef,int,CodeForces,long,fa,Lexichromatography,maxn,1876D,define
From: https://www.cnblogs.com/zltzlt-blog/p/17750878.html

相关文章

  • Codeforces Round 902 (Div. 1, based on COMPFEST 15 - Final Round) A~D
    A.HelmetsinNightLight首先注意到一个关键性质\(b_i\geq1\),这就意味着当我们花\(p\)的代价解锁了\(b_i\)最小的后,仅凭接下来的“连锁反应”就能解锁全部的点。注意到我们“连锁反应”的一定是按\(b_i\)从小到大排序后的一段前缀(因为越往后连锁代价越昂贵),找到转折点......
  • Codeforces Round 902 (Div. 2) (CF1877) B、C、D 题解
    B题目大意你要传话给\(n\)个人,每传一下话需要花费\(p\),当一个人被传话后,他可以最多传给\(a_i\)个人,每次花费\(b_i\)。问把话传给\(n\)个人的最小花费。分析首先传给第一个人只少要\(p\)下来贪心,每次让花费最小、且能够传话的人去传话。考虑建一个堆,堆内的信息是......
  • Codeforces Round 902 Div. 2 - A B C D
    目录A.GoalsofVictoryB.HelmetsinNightLightnull传送门A.GoalsofVictory对给定n-1组队伍的净得分求和取负即为最后一组队伍的净得分B.HelmetsinNightLight赛时想法假了,赛后更正对所有人按照传递花费升序排序,从小到大逐步选取先花费p为传递花费最小的居......
  • Codeforces Round #902 (Div.1)
    A注意到\(a_i\ge1\),因此我们先花\(p\)的代价买下\(b\)最小的,然后一定可以一直用当前可能的最小代价买下后续的人。不难发现这一定是最优的方案。只需要将序列排序或者用std::multiset来维护。单组数据时间复杂度\(O(n\logn)\)。https://codeforces.com/contest/1876/......
  • 【题解】CodeForces-1874/1875
    CodeForces-1875AJellyfishandUndertale一定是等待降到\(1\)或者能补满到\(a\)时才使用工具,依题意模拟即可。提交记录:Submission-CodeForcesCodeForces-1874AJellyfishandGame这种题目有点思路但是不是很会。赛时第一发写得根据奇偶性判断,\(k\)为偶数错了,然后感......
  • Codeforces Round 900 (Div. 3) E. Iva & Pav (位运算)
    CodeforcesRound900(Div.3)E.Iva&Pav//思路:10^9转换为2^32上的位,进行位运算,a[x][i]为到x为止第i位的1个数前缀和//对于与运算,如果当前i的前缀和不为r-l+1,则这一位的与运算结果为0//当找到从左往右第一个位置i为1使得k在这位为0,则与运算前缀大于k//二分查找最后一......
  • Codeforces Round 901 (Div. 2) C. Jellyfish and Green Apple (位运算)
    CodeforcesRound901(Div.2)C.JellyfishandGreenApple//思路:浮点数转二进制,a/b的结果为gcd(a,b)*最简分式(n/m)的结果//苹果能分的前提是人数得是一个2的次幂数,通过切割只能分为形同0.001的二进制小数//a/b的二进制如果在从左到右的sp位为1,则需要切割到这个情况//一个......
  • Codeforces Global Round 2
    C题结论就是每行每列不同的个数必须是偶数。D题首先注意到对于长度相同的询问,答案都是一样的。同时相同的s可以直接丢掉。那么我们将s排序之后,将相邻的差再进行排序,然后将询问从小到大处理。相当于是将这些段拼接在一起。#include<cstdio>#include<algorithm>#include<cstr......
  • 【计算几何】codeforces上面的一点简简单单的计算几何入门题
    开篇碎碎念我真的好喜欢开篇碎碎念啊(可恶真的是太话痨啦)最近有在cf上面写写题,唔不过还没上百题,过两天就可以写百题纪念啦,也还没上青,陌陌菜菜,陌陌在努力变强捏。cf1850GTheMorningStartag:用map进行维护,斜率与坐标的关系题目链接:G.TheMorningStar题意:找到一个点,使另一......
  • 「题解」Codeforces Round 883 (Div. 3)
    A.EscalatorConversationsProblem[题目](RudolphandCuttheRope)Sol&Code绳子长度大于钉子高度的要剪#include<bits/stdc++.h>typedeflonglongll;intmin(inta,intb){returna<b?a:b;}intmax(inta,intb){returna>b?a:b;}in......