题解 区域划分

传送门

人类智慧一下发现三角剖分后总有一些三角形有至少两条边是原多边形的边
要是能每次删掉这样一个多边形就可以递归子问题了
然后人类智慧一个结论:
只要多边形没有一条边的端点是同色的且每种颜色的顶点都至少出现了一次就一定有解
然后策略是每次删出现次数最多的颜色
归纳法可以证明
用 set 可以做到 \(O(n\log n)\)

其实只要保证每次删后仍满足上述性质就可以,没必要删最大的
于是可以链表做到 \(O(n)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define fir first
#define sec second
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n;
int a[N];

namespace task1{
	int cnt[N];
	set<int> s;
	struct color{
		set<int> same, diff;
		void remove(int t) {
			if (same.find(t)!=same.end()) same.erase(t);
			else if (diff.find(t)!=diff.end()) diff.erase(t);
			else assert(0);
		}
	}col[3];
	int getpre(int t) {
		auto it=s.lower_bound(t);
		if (it!=s.begin()) return *--it;
		else return *s.rbegin();
	}
	int getsuf(int t) {
		auto it=s.upper_bound(t);
		if (it!=s.end()) return *it;
		else return *s.begin();
	}
	void solve() {
		for (int i=1; i<n; ++i) if (a[i]==a[i+1]) {puts("No"); return ;}
		if (a[1]==a[n]) {puts("No"); return ;}
		for (int i=1; i<=n; ++i) ++cnt[a[i]];
		for (int i=0; i<3; ++i) if (!cnt[i]) {puts("No"); return ;}
		puts("Yes");
		a[0]=a[n]; a[n+1]=a[0];
		for (int i=1; i<=n; ++i)
			if (a[i-1]==a[i+1]) col[a[i]].same.insert(i); //, cout<<i<<": same"<<endl;
			else col[a[i]].diff.insert(i); //, cout<<i<<": diff"<<endl;
		for (int i=1; i<=n; ++i) s.insert(i);
		for (int i=1; i<=n-3; ++i) {
			int maxn=0, maxi=-1;
			for (int j=0; j<3; ++j) if (cnt[j]>maxn && col[j].diff.size()) maxn=cnt[j], maxi=j;
			// cout<<"maxi: "<<maxi<<endl;
			assert(maxi!=-1);
			int tem=*col[maxi].diff.begin();
			col[maxi].diff.erase(tem);
			int pre=getpre(tem), suf=getsuf(tem);
			printf("%d %d\n", pre, suf);
			col[a[pre]].remove(pre);
			col[a[suf]].remove(suf);
			s.erase(tem); --cnt[a[tem]];
			if (a[getpre(pre)]==a[getsuf(pre)]) col[a[pre]].same.insert(pre);
			else col[a[pre]].diff.insert(pre);
			if (a[getpre(suf)]==a[getsuf(suf)]) col[a[suf]].same.insert(suf);
			else col[a[suf]].diff.insert(suf);
		}
	}
}

signed main()
{
	freopen("divide.in", "r", stdin);
	freopen("divide.out", "w", stdout);

	n=read();
	for (int i=1; i<=n; ++i) a[i]=read();
	task1::solve();
	
	return 0;
}
posted @ 2022-07-06 19:04  Administrator-09  阅读(2)  评论(0编辑  收藏  举报