do_while_true

一言(ヒトコト)

「题解」AGC058C Planar Tree

为毛这么难理解啊?这就是 AGC 吗?


先把相邻的同色合并,不会影响答案。

2 能匹配 1 2 3,1 却只能匹配 1 2,所以 1 2 如果相邻可以直接把它俩合并成一个 2,不会影响答案,和上面类似。

现在环中一定是 \(\leq 2\) 的和 \(\geq 3\) 的交替出现。如果只剩下 2 和 3 那么直接连起来就好了。现在并不是只有 2 和 3 的请况。

跨过偶数个点也就是直接连 2 3 可以鸽到连,对其他的并没有什么影响。

然后考虑如果跨过了 \(\geq 3\) 个点,那么它内部一定需要有一个恰好跨过一个点的,否则它内部是 2 3 2 3 交替那么可以调整使得其跨过 \(\leq 1\) 个点。

那么现在考虑不断删掉跨过恰好一个点的,那么现在就只剩下这几种情况:

3 2 3,连 3 3,连 2 3,然后这一段可以看成一个 3 了。

2 3 2,连 2 2,连 3 2,然后这一段可以看成一个 2 了。

1 3 2,连 1 2,连 3 2,然后这一段可以看成一个 2 了(3 已经被堵起来了,而 2 相比 1 能够连的点更多)。

4 2 3,连 4 3,连 2 3,然后这一段可以看成一个 3 了(原因同理)。

这样就能发现,要干碎一个 4 必须要废掉一个 2,要干碎一个 1 必须废掉一个 3,然后干碎 4 还必须借一个不被废掉的 3,干碎 1 也要借一个不被废掉的 2,从而导出存在合法方案的必要条件:再进行同色,以及 1 2,3 4 的合并之后,各个数的出现次数 \(num\) 要满足 \(num_2>num_4\)\(num_3>num_1\)

然后证明它的充分性:

如果 1,4 都出现,先把环中的所有 1 和 4 都标记出来,然后将被两个 1 夹着的 3 以及被两个 4 夹着的 2 标记。设 \(cnt_x\)\(x\) 被标记的次数,由于有 \(cnt_3<cnt_1\)\(cnt_2<cnt_4\),那么一定有没有被标记的 3,考虑这个 3 的两边已经不会出现 1 3 1 的情况(否则它就会被标记),同理不会出现 4 2 4,所以没标记的 3 旁边至少有一个 2,2 旁边至少有一个 3.然后考虑剩余的没被标记的 2 3 2 3 2 3 ... 极长段,一定存在这样段,并且长度一定 \(\geq 2\)(如果 \(=1\) 的话,说明不满足上面说的旁边至少有一个 2/3 的情况),而考虑这个极长段的一头一定是 2 3 或者 3 2,它后面无论跟 1 还是 4 都出现了一次可以匹配的小区间。

如果只有 1 出现,4 不出现,那么合法,这个可以直接构造,随便选一个 2 让它和所有的 1 和 3 连起来,再让其余 2 格子和自己的旁边连边。

#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<ctime>
#include<random>
#include<assert.h>
#define pb emplace_back
#define mp make_pair
#define fi first
#define se second
#define dbg(x) cerr<<"In Line "<< __LINE__<<" the "<<#x<<" = "<<x<<'\n';
#define dpi(x,y) cerr<<"In Line "<<__LINE__<<" the "<<#x<<" = "<<x<<" ; "<<"the "<<#y<<" = "<<y<<'\n';
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>pii;
typedef pair<ll,int>pli;
typedef pair<ll,ll>pll;
typedef pair<int,ll>pil;
typedef vector<int>vi;
typedef vector<ll>vll;
typedef vector<pii>vpii;
typedef vector<pil>vpil;
template<typename T>T cmax(T &x, T y){return x=x>y?x:y;}
template<typename T>T cmin(T &x, T y){return x=x<y?x:y;}
template<typename T>
T &read(T &r){
	r=0;bool w=0;char ch=getchar();
	while(ch<'0'||ch>'9')w=ch=='-'?1:0,ch=getchar();
	while(ch>='0'&&ch<='9')r=r*10+(ch^48),ch=getchar();
	return r=w?-r:r;
}
template<typename T1,typename... T2>
void read(T1 &x,T2& ...y){read(x);read(y...);}
const int mod=998244353;
inline void cadd(int &x,int y){x=(x+y>=mod)?(x+y-mod):(x+y);}
inline void cdel(int &x,int y){x=(x-y<0)?(x-y+mod):(x-y);}
inline int add(int x,int y){return (x+y>=mod)?(x+y-mod):(x+y);}
inline int del(int x,int y){return (x-y<0)?(x-y+mod):(x-y);}
const int N=300010;
int n,a[N],m;
void solve(){
	read(n);m=0;
	for(int i=1;i<=n;i++){
		int x;read(x);
		while(m){
			if(x==a[m])--m;
			else if((x==1&&a[m]==2)||(x==2&&a[m]==1)){
				x=2;
				--m;
			}
			else if((x==3&&a[m]==4)||(x==4&&a[m]==3)){
				x=3;
				--m;
			}
			else break;
		}
		a[++m]=x;
	}
	int x=a[1];
	while(m>1){
		if(x==a[m])--m;
		else if((x==1&&a[m]==2)||(x==2&&a[m]==1)){
			x=2;
			--m;
		}
		else if((x==3&&a[m]==4)||(x==4&&a[m]==3)){
			x=3;
			--m;
		}
		else break;
	}
	a[1]=x;
	int c[5];c[1]=c[2]=c[3]=c[4]=0;
	for(int i=1;i<=m;i++)c[a[i]]++;
	if((!c[1]&&!c[4]) || (c[2]>c[4]&&c[3]>c[1]))
		puts("Yes");
	else
		puts("No");
}
signed main(){
	#ifdef do_while_true
//		assert(freopen("data.in","r",stdin));
//		assert(freopen("data.out","w",stdout));
	#endif
	int T;read(T);while(T--)solve();
    #ifdef do_while_true
		cerr<<'\n'<<"Time:"<<1.0*clock()/CLOCKS_PER_SEC*1000<<" ms"<<'\n';
	#endif
	return 0;
}
posted @ 2022-10-05 19:49  do_while_true  阅读(51)  评论(0编辑  收藏  举报