Loading

AGC058C 做题记录

复杂的 AGC 结论题 link

我们先观察一下题目,发现如果 \(A_i \in \{1, 2, 3\}\),那么一定有解:每个点找到前面最近的可连的点作为父亲,随便定个根,不难发现并不会出现交叉的情况。

对于 \(A_i \in \{1, 2, 3, 4\}\),可以直观感受到需要发现更多的性质或者进行一些视角转化。

比如对于 \(A_i = 1\) 的点,只能连到 \(A_i = 2\) 的点,\(A_i = 4\) 的点同理。假设我们已经做完了这一部分,现在又一些包含 \(2,3,12,34\) 的连通块。

对于 \(2\) 单点,我们将其极长的连续一段 \(2\) 缩起来,\(3\) 同理,这样不需要考虑 \(2\)\(3\) 单点之间的连边。

\(12\)\(2\) 连边可以取 \(1-2\)\(12\)\(3\)\(34\) 连边可以取 \(2-3\)\(34\)\(3\) 连边可以取 \(4-3\),所以一定存在一种合法方案。

所以现在的问题就是判定是否可以给每个 \(1\)\(4\) 找到连边,使得边不交叉。

同样的,先把每个极长的相同连续段缩起来。为了进一步观察本质,容易想到对于一对相邻的点 \(1,2\),可以先把 \(1\) 删掉,\(3,4\) 同理。

处理后的序列形如 \(1,3,2,4,1,4,3,\dots\)

这时候我们可以寻找极小匹配边,即影响最小的连边。比如对于三个相邻的点 \(1,3,2\),可以牺牲一个 \(3\) 来匹配 \(1,2\),相当于删掉了 \(1,3\),同理可以删掉 \(2,4\)

\(C_1,C_2,C_3,C_4\)\(4\) 种点的个数,那么必要条件为 \(C_3 > C_1, \ C_2 > C_4\)。手摸一下发现 \(C_1 = C_3, \ C_2 > C_4\) 的情况是不存在的。

其实这也是充分条件。如果当前不能再连边了,把 \(1,4\)\(2,3\) 看成两类点,则每个极长的 \(2,3\) 类点段长度只能为 \(1\),不难发现此时一定有 \(C_1 + C_4 \ge C_2 + C_3\)


这题我有一个很大的思考问题,就是把连边拍到序列上,变成了区间不交叉问题。

但是这样不利于正解的思考。具体的,我没有充分利用环的性质,比如首尾两个点相同可以忽略,这样也无法验证 \(C_1 = C_3, \ C_2 > C_4\) 这种情况是否存在。

所以思考一道问题,大思路可能只有一种,但是具体的细节思路可能有很多种,必须选择最正确的思考角度才行。

面对这种偏构造的题,分讨是常见的。还要注意细节,要冷静下来,验证每一步结论的正确性,不要一步错步步错。要大胆猜测某些分类情况是不会出现的,充分利用题目性质。

以及最开始的一些剪枝去叶,个人认为这不是去皮看本质,应该是将这个问题分成两部分,一部分比较容易,这样只需要思考另一部分,也可以看作是弱化转化。


点击查看代码
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned ll
#define fi first
#define se second
#define mkp make_pair
#define pir pair <ll, ll>
#define pb push_back
#define i128 __int128
using namespace std;
char buf[1 << 22], *p1, *p2;
// #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, (1 << 22) - 10, stdin), p1 == p2)? EOF : *p1++)
template <class T>
const inline void rd(T &x) {
    char ch; bool neg = 0;
    while(!isdigit(ch = getchar()))
        if(ch == '-') neg = 1;
    x = ch - '0';
    while(isdigit(ch = getchar()))
        x = (x << 1) + (x << 3) + ch - '0';
    if(neg) x = -x;
}
const ll maxn = 3e5 + 10, inf = 1e9, mod = 998244353;
ll power(ll a, ll b = mod - 2) {
	ll s = 1;
	while(b) {
		if(b & 1) s = 1ll * s * a %mod;
		a = 1ll * a * a %mod, b >>= 1;
	} return s;
}
template <class T, class _T>
const inline ll pls(const T x, const _T y) { return x + y >= mod? x + y - mod : x + y; }
template <class T, class _T>
const inline void add(T &x, const _T y) { x = x + y >= mod? x + y - mod : x + y; }
template <class T, class _T>
const inline void chkmax(T &x, const _T y) { x = x < y? y : x; }
template <class T, class _T>
const inline void chkmin(T &x, const _T y) { x = x < y? x : y; }

ll T, n, a[maxn];

void solve() {
	rd(n);
	for(ll i = 1; i <= n; i++) rd(a[i]);
	ll m = 1;
	for(ll i = 2; i <= n; i++) {
		a[++m] = a[i];
		while(m > 1 && (a[m - 1] == a[m] ||
			 a[m - 1] + a[m] == 3 || a[m - 1] + a[m] == 7)) {
			if(a[m - 1] == 1 && a[m] == 2
			 || a[m - 1] == 4 && a[m] == 3) a[m - 1] = a[m];
			--m;
		}
	} ll l = 1, r = m;
	while(l < r && (a[l] == a[r] || a[l] + a[r] == 3 || a[l] + a[r] == 7)) {
		if(a[l] == a[r] || a[l] == 1 || a[l] == 4) ++l;
		else --r;
	}
	ll cnt[5] = {};
	for(ll i = l; i <= r; i++) ++cnt[a[i]];
	puts(cnt[3] > cnt[1] && cnt[2] > cnt[4]? "Yes" : "No");
}

int main() {
	rd(T); while(T--) solve();
	return 0;
}
posted @ 2025-04-10 20:23  Sktn0089  阅读(9)  评论(0)    收藏  举报