21.6.24 t1
tag:构造
答案为no只有两种情况:
- 有一个颜色没有出现过
- 两个相邻的点同色
其他情况一定是yes。
具体构造方案为:每次找到一组连续 \(3\) 不同色的点,且中间那个点的颜色出现多于1次,然后将这个三角形切掉,继续递归处理。
这样一次操作之后显然是不会违反上述性质的。
代码实现可以使用一个数组维护可能作为中间点的那些点。
一次删除操作最多只会影响到2个点,所以空间开3倍就够了。
#include<bits/stdc++.h>
using namespace std;
template<typename T>
inline void Read(T &n){
char ch; bool flag=false;
while(!isdigit(ch=getchar()))if(ch=='-')flag=true;
for(n=ch^48;isdigit(ch=getchar());n=(n<<1)+(n<<3)+(ch^48));
if(flag)n=-n;
}
enum{
MAXN = 100005
};
int n, a[MAXN], l[MAXN], r[MAXN];
int q[3*MAXN], top, cnt[3];
char vis[MAXN];
inline void check(int x){if(a[l[x]]!=a[x] and a[x]!=a[r[x]] and a[r[x]]!=a[l[x]]) vis[x] = true, q[++top] = x;}
inline void del(int x){
printf("%d %d\n",l[x],r[x]);
r[l[x]] = r[x]; l[r[x]] = l[x];
vis[l[x]] = vis[r[x]] = vis[x] = false;
cnt[a[x]]--;
check(l[x]); check(r[x]);
}
int main(){
Read(n);
for(int i=1; i<=n; i++) Read(a[i]);
for(int i=2; i<=n; i++) l[i] = i-1; l[1] = n;
for(int i=1; i<n; i++) r[i] = i+1; r[n] = 1;
for(int i=1; i<=n; i++) check(i), cnt[a[i]]++;
for(int i=0; i<3; i++) if(cnt[i]==0) return puts("no"), 0;
for(int i=1; i<n; i++) if(a[i]==a[i+1]) return puts("no"), 0;
if(a[1]==a[n]) return puts("no"), 0;
puts("yes");
for(int i=1, rem=n; i<=top and rem>3; i++) if(cnt[a[q[i]]]>1 and vis[q[i]]) del(q[i]), rem--;
return 0;
}