首页 > 其他分享 >Codeforces Round 968 (Div. 2)

Codeforces Round 968 (Div. 2)

时间:2024-08-26 21:47:33浏览次数:10  
标签:ll int max sum 968 Codeforces ++ Div mx

A. Turtle and Good Strings

题意:确定是否存在一种方案使得 \(s = t_1 + t_2 + \cdots + t_m\),满足 \(m > 1\) 且任意 \(i < j\),\(t_i\) 的第一个字母不等于 \(t_j\) 的最后一个字母。

\(s_1\) 和 \(s_n\) 一定不属于一个子串,因此 \(s_1 \ne s_n\) 是条件非法的必要条件。

那么反之是否能构造一组解呢?这是显然的,取 \(t_1 = s[1], t_2 = s[2, n]\) 即可。

void solve() {
	int n; string s; cin >> n >> s;
	cout << (s.front() != s.back() ? "Yes\n" : "No\n");
}

B. Turtle and Piggy Are Playing a Game 2

题意:Alice 和 Bob 进行博弈,Alice 先手。

每次 Alice 可以选一个 \(i\) 并删掉 \(i, i + 1\) 中较小的一个,Bob 可以选一个 \(i\) 并删掉 \(i, i + 1\) 中较大的一个。

Alice 想最大化 \(a_1\),Bob 想最小化 \(a_1\),求两人都在最优策略下的 \(a_1\)。

策略很明了了,Alice 每次删掉全局最小,Bob 每次删掉全局最大,删到最后只剩整个序列的中位数。

void solve() {
	cin >> n;
	for(int i = 1; i <= n; ++ i) cin >> a[i];
	sort(a + 1, a + n + 1);
	cout << a[n / 2 + 1] << '\n';
}

C. Turtle and Good Pairs

题意:\((i, j)\) 是好的当且仅当 \(i < j\) 且存在 \(k \in [i, j)\) ,满足 \(s_k \ne s_{k + 1}\) 且 \(s_i \ne s_k \lor s_{j} \ne s_{k + 1}\)。将 \(s\) 重新排序,最大化好的数对个数。

把字符串分为若干极长连续颜色段 \([l_i, r_i]\)(如 \(aaabbcc = [aaa][bb][cc]\))。

容易发现 \((i, j)\) 是好的的充要条件为 \(i, j\) 所在颜色段不相邻。

令 \(a_i = r_i - l_i + 1\),那么好的数对个数等于 \(\dfrac{n(n - 1)}{2} - \sum a_{i}a_{i + 1}\)。

目标转化为最小化 \(\sum a_i a_{i + 1}\)。

当字符集大小不为 \(1\) 时,可以证明 \(\sum a_i a_{i + 1} \ge n - 1\) 并且这个下界是可以达到的。

如果存在 \(a_k = 1\):

\[\sum_{i = 1}^{m - 1}a_ia_{i + 1} \ge \sum_{i = 1}^{k - 1}a_i + \sum_{i = k}^{m - 1}a_{i + 1} \ge n - a_k \]

如果 \(\forall a_k \ge 2\),\(a_ia_{i + 1} \ge1 a_i + a_{i + 1}\):

\[\sum_{i = 1}^{m - 1}a_ia_{i + 1} \ge \sum_{i = 1}^{m - 1}a_i + \sum_{i = 2}^{m}a_{i} > n \]

我们让前面所有 \(a_i = 1\),最后一个连续段放多出来的相同字母(如 \(aaabbcc = ababacc\)),显然有 \(\sum a_ia_{i + 1} = n - 1\)。

时间复杂度 \(O(26n)\)

void solve() {
	cin >> n >> s;
	for(auto x : s) ++ cnt[x - 'a'];
	int Len = 0;
	
	string t;
	
	while(Len < n) {
		for(int i = 0; i < 26; ++ i) {
			if(cnt[i]) {
				-- cnt[i], ++ Len;
				t += char(i + 'a');
			}
		}
	}
	cout << t << '\n';
}

D1. Turtle and a MEX Problem (Easy Version)

题意:给定 \(n\) 个序列 \([a_i]\),\(f(x)\) 定义为 \(x\) 经过若干次操作(可能不操作)达到的最大值。

一次操作定义为:选定一个序列 \([a_i]\),\(x \gets \text{mex}(x \cup [a_i])\)。在简单版中,一个序列可以被重复选择。

给定 \(m \le 10^9\),求 \(\sum_{x = 0}^{m} f(x)\)。

定义 \(u_i = \text{mex}[a_i],\ v_i = \text{mex}\big([a_i] \cup u_i\big)\)。

我们发现不管是什么 \(x\),不管对 \([a_i]\) 操作几次,能够达到且一定能达到的只有 \(v_i\) 和 \(u_i\)。

因此 \(f(x) = \max\big(x, \max v_i\big)\)。

ll sum(ll l, ll r) {
	if(l > r) return 0;
	return (l + r) * (r - l + 1) / 2;
}
void solve() {
	int n, m, mx = 0; cin >> n >> m;
	ll ans = 0;
	while(n --) {
		int k; cin >> k;
		set<int> se;
		for(int i = 0; i <= k + 1; ++ i) {
			se.ep(i);
		}
		for(int i = 0; i < k; ++ i) {
			int x; cin >> x;
			se.erase(x);
		}
		mx = max(mx, *++ se.begin());
	}
	cout << mx * ll(min(m, mx) + 1) + sum(mx + 1, m) << '\n';
}

D2. Turtle and a MEX Problem (Hard Version)

题意与 D1 相同,多了每个序列只能选一次的限制。

如果 \(x = u_i\),那么 \(x\) 能够走到 \(v_i\)。

不难想到 \(u_i\) 向 \(v_i\) 连边。

如果 \(x = u_i\),那么 \(x \to v_i\) 后是可以继续走 \(v_i\) 的出边的,因为一个序列只会产生一条边, \(v_i\) 的出边对应的序列不是 \(i\)。

定义 \(f_i\) 表示 \(i\) 能到达的最大点坐标,可以逆拓扑序完成。

  • 一个 \(x\) 的答案至少是 \(f_i\)。
  • 一个 \(x\) 的答案至少是 \(\max u_i\)。
  • 如果 \(i\) 只有一条出边,只有 \(x = i\) 能够到达 \(f_i\)。
  • 如果存在 \(i\) 有大于一条出边,那么对于任意 \(x\),我们可以先走另一条出边对应的序列来达到 \(i\),然后再走通向 \(f_i\) 的出边。
ll sum(ll l, ll r) {
	if(l > r) return 0;
	return (l + r) * (r - l + 1) / 2;
}

void solve() {
	int n, m; cin >> n >> m;
	ll ans = 0;
	
	vector<vector<int>> g(2 * n);
	vector<int> d(2 * n), w(2 * n), val(2 * n);
	
	int idx = 0, mx = 0;
	map<int, int> mp;
	
	while(n --) {
		int k; cin >> k;
		set<int> se;
		for(int i = 0; i <= k + 3; ++ i) {
			se.ep(i);
		}
		for(int i = 0; i < k; ++ i) {
			int x; cin >> x;
			se.erase(x);
		}
		int p1 = *se.begin(), p2 = *++ se.begin();
		int x = 0, y = 0;
		
		(mp.count(p1)) ? x = mp[p1] : val[x = mp[p1] = idx ++] = p1;
		(mp.count(p2)) ? y = mp[p2] : val[y = mp[p2] = idx ++] = p2;
		
		mx = max(mx, p1);
		
		g[y].eb(x), ++ d[x];
	}
	queue<int> q;
	vector<int> vec;
	
	for(int i = 0; i < idx; ++ i) {
		if(!d[i]) {
			q.ep(i);
		}
		if(d[i] > 1) vec.eb(i);
	}
	while(!q.empty()) {
		int x = q.front();
		q.pop();
		w[x] = max(w[x], val[x]);
		for(int y : g[x]) {
			w[y] = max(w[y], w[x]);
			if(!-- d[y]) q.ep(y);
		}
	}
	for(int i : vec) mx = max(mx, w[i]);
	
	vector<int> id(idx);
	iota(id.begin(), id.end(), 0);
	
	sort(id.begin(), id.end(), [&](int i, int j) {
		return val[i] < val[j];
	});
	
	int lst = 0;
	for(int i = 0; i < idx; ++ i) {
		
		int x = id[i];
		if(val[x] > m) break;
		
		int l = lst, r = val[x] - 1;
		
		ans += max(min(mx, r) - l + 1, 0) * (ll)mx + sum(max(l, mx + 1), r);
		ans += max(mx, w[x]);
		
		lst = val[x] + 1;
	}
	int l = lst, r = m;
	ans += max(min(mx, r) - l + 1, 0) * (ll)mx + sum(max(l, mx + 1), r);
	
	cout << ans << '\n';
}

E1. Turtle and Inversions (Easy Version)

标签:ll,int,max,sum,968,Codeforces,++,Div,mx
From: https://www.cnblogs.com/Luxinze/p/18381658

相关文章

  • Codeforces Round 968 (Div. 2)
    A.TurtleandGoodStrings思路:题意大致为把一个字符串分成若干段,要求每两段,前一段的首字符不能等于后的一段的尾字符,给你一个字符串,能不能构造出合法方案。观察到,分的段数越小,越有助于我们判断。所以,不妨分成两段,问题转化为判断首尾字符是否相等。代码:#include<bits/stdc++.......
  • [ARC182C] Sum of Number of Divisors of Product 题解
    题目链接点击打开链接题目解法我怎么不会分治/fn首先把\(x\)分解成\(\prodp_i^{x_i}(0\lei\le5)\)的形式,正因数个数为\(\prod(x_i+1)\)有一个很牛的想法是:合并两个\(x_i\)序列(假设一个叫\(x_0,...,x_5\),另一个叫\(y_0,...,y_5\))先不考虑后面的\(+1\)(可以最后......
  • Codeforces Round 968 (Div. 2)
    良心出题人给了中文题解!!!A.TurtleandGoodStrings长度为\(n\)的字符串至少分成两段,使\(\foralli<j\),第\(i\)段的首字符不等于第\(j\)段的尾字符第一个字符一定作为首字符,最后一个字符一定作为尾字符,只要判断这两个字符是否相等即可相等的话一定无解,不相等一定有......
  • EPIC Institute of Technology Round August 2024 (Div. 1 + Div. 2)
    Preface两个礼拜前打的比赛拖到现在才写博客,我只能说也是个神人了这场其实D2很快就想到做法了,但自己把自己给否了,后面不管了实现了一发交上去发现过了然后这天由于12点左右室友就关灯睡觉了,我写完D2后看了眼E没仔细想就睡觉去了,后面发现E其实很trivialA.Distance......
  • Codeforces Round #900 (Div. 3)
    三年之后第一次打比赛,用小号打了场\(Div.3\),居然没有AK,感觉实力退步到小学了。A.HowMuchDoesDaytonaCost?若只判断题,只要判断\(\{a_n\}\)中是否存在\(k\)即可。B.AleksaandStack构造方法不唯一,我直接输出奇数列,显然正确。C.VasilijeinCacak若只判断题......
  • Codeforces Round 967 (Div. 2) - C
    题意概述这是一个交互题。有一棵有\(n\)个节点的树,节点编号从\(1\)到\(n\),并要求你使用以下类型的查询来猜测它:"?ab"会告诉你哪个节点\(x\)在点\(a\)和\(b\)之间(\(|d(a,x)-d(b,x)|\)的值最小),其中\(d(x,y)\)是节点\(x\)和\(y\)之间的距离。如果存在不......
  • CodeForces - 1353D Constructing the Array
    CodeForces-1353D这道题也可能比较简单,主要是要想到优先队列要怎么使用,这一点如果用递归会写不了但是因为对优先队列不太熟悉,只有被提示可以用优先队列才想到要怎么用,还是很重要的STL注意运算符的重构应该反着来写其他的思维很朴素,运算符的重构就是,先比较长度,优先用长度长......
  • CodeForces-431C k-Tree
    感觉这个题的dp还是有点思维的,可能就是我现在能做到的题目的天花板级别的了,dp还是要点灵感感觉,以下是代码,可能要写题解要过好久,先水着include<bits/stdc++.h>defineintlonglongdefineendl'\n'usingnamespacestd;constintmod=1000000007;intn,k,d;intdp[200][2]=......
  • CodeForces - 1336A Linova and Kingdom
    CodeForces-1336A就差一点点,很可惜,少发现个很显而易见的结论就是一个点的价值,实际上就是(这个点的深度-之后的点的数目)就是\(depth_i-size_i\)然后只要用dfs维护就好了然后把一个点的价值用STL优先队列放在一起,贪心完成。但是可能也算不上什么贪心,因为是很朴素的东西......
  • Codeforces Round 967 (Div. 2)
    A.MakeAllEqual签到题,先确定最终答案,然后把其他数删去,转化为统计众数点击查看代码#include<bits/stdc++.h>usingnamespacestd;#definelllonglong#defineullunsignedlonglongintread(){intx=0;boolf=false;charc=getchar();while(c<......