「题解」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;
}