Codeforces Round 879 (Div. 2) 题解

寄!大!了!

Rating -= 124.

image

(恼)

https://codeforces.com/contest/1834

https://codeforces.com/contest/1834/problems

C. Game with Reversing

发现 \(\text{rev}(S) \to S\)\(\text{rev}(T) \to T\) 本质上是一样的。

赛时就一个劲的对着 \(S\) 操作,,,。

我们考虑单点修改在 \(S\) 上做,翻转操作在 \(T\) 上做。

\(\displaystyle diff(S, T) = \sum_{i = 1} ^ {|S|} [S_i \neq T_i]\)

  • \(T\) 的翻转次数为偶数,答案就是 \(diff(S, T)\) 再加上翻转次数,如果翻转次数是奇数,就再加 \(1\)。(注:翻转次数 = \(\max(0, diff(S, T) - 1)\)。)

  • \(T\) 的翻转次数为奇数,答案就是 \(diff(S, \text{rev}(T))\) 再加上翻转次数,如果翻转次数是偶数,就再加 \(1\);如果 \(diff(S, \text{rev}(T)) = 0\),答案就是 \(2\)。(注:翻转次数 = \(\max(0, diff(S, \text{rev}(T)) - 1)\)。)

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
bool Memory_Begins;
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
template < class Z >
inline void read (Z &tmp) {
	Z x = 0, f = 0;
	char c = getchar ();
	for ( ; c < '0' || c > '9' ; c = getchar ()) f |= (c == '-');
	for ( ; c >= '0' && c <= '9' ; c = getchar ()) x = (x << 1) + (x << 3) + (c & 15);
	tmp = !f ? x : -x;
}
const int N = 1e5 + 5;
char s[N], t[N];
int n;
inline int solve_z () {
	int ans = 0;
	for (int i = 1;i <= n; ++ i) ans += (s[i] != t[i]);
	int rev = ans > 0 ? ans - 1 : 0;
	if (rev % 2) rev += !ans ? 2 : 1;
	return ans + rev;
}
inline int solve_f () {
	int ans = 0;
	for (int i = 1;i <= n; ++ i) ans += (s[i] != t[n - i + 1]);
	int rev = ans > 0 ? ans - 1 : 0;
	if (rev % 2) ; else rev += !ans ? 2 : 1; 
	return ans + rev; 	
}
bool Memory_Ends;
signed main () {
	fprintf (stderr, "%.3lf MB\n", (&Memory_Begins - &Memory_Ends) / 1048576.0);
	int _;
	read (_);
	while (_ --) {
		read (n);
		scanf ("%s", s + 1);
		scanf ("%s", t + 1);
		printf ("%d\n", min (solve_z (), solve_f ()));
	}
	fprintf (stderr, "%.3lf ms\n", 1e3 * clock () / CLOCKS_PER_SEC);
	return 0;
}
/*
Things to check:
1. int ? long long ? unsigned int ? unsigned long long ?
2. array size ? is it enough ?
*/

D. Survey in Class

枚举最大值区间 \([l, r]\) 和最小值区间 \([l', r']\)

  • \([l, r]\)\([l', r']\) 无交集

贪心可得答案就是 \(2\max(r - l + 1, r' - l' + 1)\)

  • \([l, r]\) 包含 \([l', r']\)

贪心可得答案为 \(2(r - l + 1) - 2(r' - l' + 1)\)

这时枚举 \([l', r']\),对于每一个左端点 \(\leq l'\) 的区间 \([L, R]\)\(\max(a_R, R - L + 1) \to a_R\),然后计算 \([r', +\infty]\) 的最大值,就是 \(r - l + 1\) 的最大值。

  • \([l, r]\)\([l', r']\) 有交集

答案是独立部分的最大值的 \(2\) 倍。(独立部分指的是非交集并且有 \([l, r]\)\([l', r']\) 覆盖)

枚举 \([l, r]\),二分前缀公共部分和后缀公共部分,设对于任意的满足条件的 \([l', r']\),最短的长度为 \(k\),那么可以直接产生贡献 \(2(r - l + 1 - k)\)

因为如果 \([l, r]\)\([l', r']\) 有交集,按这样的枚举方式,枚举 \([l, r]\) 时一定会有 \([l', r']\),枚举 \([l', r']\) 时一定会有 \([l, r]\),所以这样做是对的。

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
bool Memory_Begins;
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
template < class Z >
inline void read (Z &tmp) {
	Z x = 0, f = 0;
	char c = getchar ();
	for ( ; c < '0' || c > '9' ; c = getchar ()) f |= (c == '-');
	for ( ; c >= '0' && c <= '9' ; c = getchar ()) x = (x << 1) + (x << 3) + (c & 15);
	tmp = !f ? x : -x;
}
struct max_seg {
	int mx[200005 << 2];
	inline void push_up (int u) {mx[u] = max (mx[u << 1], mx[u << 1 | 1]);}
	inline void build (int u, int l, int r) {
		if (l == r) {mx[u] = 0; return ;}
		int mid = l + r >> 1;
		build (u << 1, l, mid), build (u << 1 | 1, mid + 1, r);
		push_up (u);
	}
	inline void modify (int u, int l, int r, int x, int y) {
		if (l == r) {mx[u] = y; return ;}
		int mid = l + r >> 1;
		if (x <= mid) modify (u << 1, l, mid, x, y);
		else modify (u << 1 | 1, mid + 1, r, x, y);
		push_up (u);
	}
	inline int query (int u, int l, int r, int x, int y) {
		if (x <= l && r <= y) return mx[u];
		int ans = 0, mid = l + r >> 1;
		if (x <= mid) ans = max (ans, query (u << 1, l, mid, x, y));
		if (y > mid) ans = max (ans, query (u << 1 | 1, mid + 1, r, x, y));
		return ans;
	}
} seg;
struct ST {
	int mx[200005][20], lg[200005], a[200005], n;
	inline void pre () {
		lg[0] = -1;
		for (int i = 1;i <= n; ++ i) lg[i] = lg[i >> 1] + 1;
		for (int i = 1;i <= n; ++ i) mx[i][0] = a[i];
		for (int j = 1;j <= 19; ++ j) {
			for (int i = 1;i + (1 << j) - 1 <= n; ++ i) {
				mx[i][j] = max (mx[i][j - 1], mx[i + (1 << (j - 1))][j - 1]);
			}
		}
	}
	inline int query (int L, int R) {
		int k = lg[R - L + 1];
		return max (mx[L][k], mx[R - (1 << k) + 1][k]);
	}
} biu;
struct ST2 {
	int mn[200005][20], lg[200005], a[200005], n;
	inline void pre () {
		lg[0] = -1;
		for (int i = 1;i <= n; ++ i) lg[i] = lg[i >> 1] + 1;
		for (int i = 1;i <= n; ++ i) mn[i][0] = a[i];
		for (int j = 1;j <= 19; ++ j) {
			for (int i = 1;i + (1 << j) - 1 <= n; ++ i) {
				mn[i][j] = min (mn[i][j - 1], mn[i + (1 << (j - 1))][j - 1]);
			}
		}
	}
	inline int query (int L, int R) {
		int k = lg[R - L + 1];
		return min (mn[L][k], mn[R - (1 << k) + 1][k]);
	}
} biu2;
int n, m, l[100005], r[100005], sq[200005], le[200005], ri[200005], M;
vector < int > st[200005];
map < int, int > ys;
bool Memory_Ends;
signed main () {
	fprintf (stderr, "%.3lf MB\n", (&Memory_Begins - &Memory_Ends) / 1048576.0);
	int _; read (_);
	while (_ --) {
		read (n), read (m);
		ys.clear ();
		M = 0;
		for (int i = 1;i <= n; ++ i) {
			read (l[i]), read (r[i]);
			sq[++ M] = l[i], sq[++ M] = r[i];
		} 
		sort (sq + 1, sq + 1 + M);
		M = unique (sq + 1, sq + 1 + M) - sq - 1;
		for (int i = 1;i <= M; ++ i) ys[sq[i]] = i;
		for (int i = 1;i <= n; ++ i) l[i] = ys[l[i]], r[i] = ys[r[i]];
		for (int i = 0;i <= M + 1; ++ i) le[i] = 0, ri[i] = 0;
		for (int i = 1;i <= n; ++ i) le[l[i]] ++, ri[r[i]] ++;
		for (int i = 1;i <= M; ++ i) ri[i] += ri[i - 1];
		for (int i = M;i >= 1; -- i) le[i] += le[i + 1];
		ll ans = 0;
		seg.build (1, 1, M);
		for (int i = 1;i <= M; ++ i) st[i].clear ();
		for (int i = 1;i <= n; ++ i) st[l[i]].push_back (i);  
		for (int i = 1;i <= n; ++ i) {
			if (ri[l[i] - 1] || le[r[i] + 1]) ans = max (ans, 2ll * ((ll) (sq[r[i]] - sq[l[i]] + 1)));
		}
		for (int i = 1;i <= M; ++ i) {
			for (int range : st[i]) {
				int L = l[range], R = r[range];
				L = sq[L], R = sq[R];
				if (seg.query (1, 1, M, r[range], r[range]) < R - L + 1) {
					seg.modify (1, 1, M, r[range], R - L + 1); 
				}
			}
			for (int range : st[i]) {
				int w = seg.query (1, 1, M, r[range], M);
				ll cur = 1ll * w;
				int L = l[range], R = r[range];
				L = sq[L], R = sq[R];
				cur -= (ll) (R - L + 1);
				cur *= 2;
				ans = max (ans, cur);
			}
		}
		biu.n = M;
		for (int i = 1;i <= M; ++ i) biu.a[i] = 0;
		for (int i = 1;i <= n; ++ i) {
			auto &tmp = biu.a[l[i]];
			tmp = max (tmp, r[i]);
		}
		biu.pre ();
		for (int i = 1;i <= n; ++ i) {
			int L = l[i], R = r[i];
			if (biu.query (l[i], r[i]) <= r[i]) continue; 
			while (R - L > 1) {
				int mid = L + R >> 1;
				if (biu.query (mid, r[i]) > r[i]) L = mid;
				else R = mid; 
			}
			int rgmx = -1;
			if (biu.query (R, r[i]) > r[i]) rgmx = R;
			else rgmx = L;
			if (l[i] < rgmx) {
				ll cur = 1ll * (sq[r[i]] - sq[l[i]] + 1);
				cur -= 1ll * (sq[r[i]] - sq[rgmx] + 1);
				cur *= 2;
				ans = max (ans, cur); 
			}
		}  
		biu2.n = M;
		for (int i = 1;i <= M; ++ i) biu2.a[i] = M + 1;
		for (int i = 1;i <= n; ++ i) {
			auto &tmp = biu2.a[r[i]];
			tmp = min (tmp, l[i]);
		}		
		biu2.pre ();
		for (int i = 1;i <= n; ++ i) {
			int L = l[i], R = r[i];
			if (biu2.query (l[i], r[i]) >= l[i]) continue;
			while (R - L > 1) {
				int mid = L + R >> 1;
				if (biu2.query (l[i], mid) < l[i]) R = mid;
				else L = mid; 
			}
			int rgmn = -1;
			if (biu2.query (l[i], L) < l[i]) rgmn = L;
			else rgmn = R;
			if (r[i] > rgmn) {
				ll cur = 1ll * (sq[r[i]] - sq[l[i]] + 1);
				cur -= 1ll * (sq[rgmn] - sq[l[i]] + 1);
				cur *= 2;
				ans = max (ans, cur);				
			}
		}
		printf ("%lld\n", ans);
	}
	fprintf (stderr, "%.3lf ms\n", 1e3 * clock () / CLOCKS_PER_SEC);
	return 0;
}
/*
Things to check:
1. int ? long long ? unsigned int ? unsigned long long ?
2. array size ? is it enough ?
*/

E. MEX of LCM

我们发现 LCM 肯定不会太多。

如果 LCM 大于一定值,那就 break。

考虑左端点是 \(i\),现在延伸到 \(u\),LCM 为 \(w\),那么就跳过 最大的 \(v\) 使得 \([u, v]\) 满足 LCM 能被 \(w\) 整除,然后跳到 \(v + 1\),毛估估这样跳区间的次数是 \(\log A\) 级别的,二分 \(v\) 的时间是 \(\log n\),枚举左端点是 \(n\) 级别的,所以总复杂度是 \(O(n \log A \log n)\) 的。

其中这个 \(A\) 指的是 MEX 的最大值。

Conclusion. \(A\) 不超过 \(n \times (2 \log n + 1)\)

Proof. 设这些 LCM (固定左端点)是 \(x_1, x_2, \dots, x_k\),因为 \(x_i \bmod x_{i - 1} = 0 (i > 1)\),所以 \(x_i \geq 2 x_{i - 1}(i > 1)\),因为 \(x_k \leq n^2\),因为 MEX 一定不会超过子数组数量加 \(1\),所以 \(k \leq \log(n^2) + 1\),即 \(k \leq 2 \log n + 1\)

所以 \(A \leq n \times (2 \log n + 1)\)

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
bool Memory_Begins;
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
template < class Z >
inline void read (Z &tmp) {
	Z x = 0, f = 0;
	char c = getchar ();
	for ( ; c < '0' || c > '9' ; c = getchar ()) f |= (c == '-');
	for ( ; c >= '0' && c <= '9' ; c = getchar ()) x = (x << 1) + (x << 3) + (c & 15);
	tmp = !f ? x : -x;
}
const ll lim = 11216800;
inline ll gcd (ll a, ll b) {return b == 0 ? a : gcd (b, a % b);}
inline ll lcm (ll a, ll b) {
	if (a > lim || b > lim) return lim + 1;
	ll w = a / gcd (a, b);
	if (w > lim / b + 4) return lim + 1;
	else return w * b > lim ? lim + 1 : w * b; 
}
int n, a[300005], st[300005][20];
int s[lim + 1];
int pb[lim + 2], cnt;
bool Memory_Ends;
signed main () {
	fprintf (stderr, "%.3lf MB\n", (&Memory_Begins - &Memory_Ends) / 1048576.0);
	int _;
	read (_);
	while (_ --) {
		read (n);
		for (int i = 1;i <= n; ++ i) read (a[i]), st[i][0] = a[i];
		for (int j = 1;j < 20; ++ j) {
			for (int i = 1;i + (1 << j) - 1 <= n; ++ i) {
				st[i][j] = lcm (st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
			}
		}
		cnt = 0;
		for (int i = 1;i <= n; ++ i) {
			int w = st[i][0], u = i + 1;
			while (w <= lim) {
				if (!s[w]) s[w] = 1, pb[++ cnt] = w;
				for (int j = 19;j >= 0; -- j) {
					if (u + (1 << j) - 1 > n) continue;
					if (w % st[u][j] != 0) continue;
					u += (1 << j);
				}
				if (u > n) break;
				w = lcm (w, st[u ++][0]);
			}
		}
		int ans = 1;
		while (s[ans]) ans ++;
		printf ("%d\n", ans);
		for (int i = 1;i <= cnt; ++ i) s[pb[i]] = 0;
	} 
	fprintf (stderr, "%.3lf ms\n", 1e3 * clock () / CLOCKS_PER_SEC);
	return 0;
}
/*
Things to check:
1. int ? long long ? unsigned int ? unsigned long long ?
2. array size ? is it enough ?
*/
posted @ 2023-06-19 22:31  CountingGroup  阅读(33)  评论(0编辑  收藏  举报