本场题目确实逆天,前三题赛时无人切,最高分不过一百左右。仍然是一如既往的菜,又爆零了,什么时候才能走出这个圈啊……

\(T1:Polygon\)
2023/2/22 模拟赛-小白菜博客
考场上一眼计算几何,直接毙掉不做。考完后发现很简单……
正解方法确实抽象……首先,把输入的整点分为 \((奇,奇)\)\((奇,偶)\)\((偶,偶)\)\((偶,奇)\),这四种类型的点。考虑到只需输出 \(\lfloor \frac{n}{10}\rfloor\),个点,相对来说不多。又因为是凸多边形,因此考虑按照点两个坐标的奇偶性配对,使得两点的中点为整点,输出即可。

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN = 1e6;
int n,T;
vector<pair<int,pair<int,int> > > ty1,ty2,ty3,ty4;
map<pair<int,int>,bool> m;
signed main(){
	scanf("%lld",&T);
	while(T--){
		ty1.clear(),ty2.clear(),ty3.clear(),ty4.clear();
		bool flag = 0;
		scanf("%lld",&n);
		for(int i = 1; i <= n; i++){
			int u,v;
			scanf("%lld%lld",&u,&v);
			if(abs(u) % 2 == 1){
				if(abs(v) % 2 == 1)ty1.push_back(make_pair(i,make_pair(u,v)));
				else ty2.push_back(make_pair(i,make_pair(u,v)));
			}
			else{
				if(abs(v) % 2 == 1)ty3.push_back(make_pair(i,make_pair(u,v)));
				else ty4.push_back(make_pair(i,make_pair(u,v)));
			}
		}
		int cnt = 0;
		for(int i = 0; i < ty1.size(); i++){
			int x1 = ty1[i].second.first,y1 = ty1[i].second.second;
			for(int j = i + 1; j < ty1.size(); j++){
				int x2 = ty1[j].second.first,y2 = ty1[j].second.second;
				if(abs(ty1[i].first - ty1[j].first) == 1)continue;
				int x3 = (x1 + x2) / 2,y3 = (y1 + y2) / 2;
				if(m.find(make_pair(x3,y3)) != m.end())continue;
				m[make_pair(x3,y3)] = 1;
				printf("%lld %lld\n",x3,y3);
				++cnt;
				if(cnt == n / 10){
					flag = 1;
					break;
				}
			}
			if(flag)break;
		}
		if(flag)continue;
		for(int i = 0; i < ty2.size(); i++){
			int x1 = ty2[i].second.first,y1 = ty2[i].second.second;
			for(int j = i + 1; j < ty2.size(); j++){
				int x2 = ty2[j].second.first,y2 = ty2[j].second.second;
				if(abs(ty2[i].first - ty2[j].first) == 1)continue;
				int x3 = (x1 + x2) / 2,y3 = (y1 + y2) / 2;
				if(m.find(make_pair(x3,y3)) != m.end())continue;
				m[make_pair(x3,y3)] = 1;
				printf("%lld %lld\n",x3,y3);
				++cnt;
				if(cnt == n / 10){
					flag = 1;
					break;
				}
			}
			if(flag)break;
		}
		if(flag)continue;
		for(int i = 0; i < ty3.size(); i++){
			int x1 = ty3[i].second.first,y1 = ty3[i].second.second;
			for(int j = i + 1; j < ty3.size(); j++){
				int x2 = ty3[j].second.first,y2 = ty3[j].second.second;
				if(abs(ty3[i].first - ty3[j].first) == 1)continue;
				int x3 = (x1 + x2) / 2,y3 = (y1 + y2) / 2;
				if(m.find(make_pair(x3,y3)) != m.end())continue;
				m[make_pair(x3,y3)] = 1;
				printf("%lld %lld\n",x3,y3);
				++cnt;
				if(cnt == n / 10){
					flag = 1;
					break;
				}
			}
			if(flag)break;
		}
		if(flag)continue;
		for(int i = 0; i < ty4.size(); i++){
			int x1 = ty4[i].second.first,y1 = ty4[i].second.second;
			for(int j = i + 1; j < ty4.size(); j++){
				int x2 = ty4[j].second.first,y2 = ty4[j].second.second;
				if(abs(ty4[i].first - ty4[j].first) == 1)continue;
				int x3 = (x1 + x2) / 2,y3 = (y1 + y2) / 2;
				if(m.find(make_pair(x3,y3)) != m.end())continue;
				m[make_pair(x3,y3)] = 1;
				printf("%lld %lld\n",x3,y3);
				++cnt;
				if(cnt == n / 10){
					flag = 1;
					break;
				}
			}
			if(flag)break;
		}
	}
}
//1 
//11 
//0 0 
//1 1 
//2 3 
//2 5 
//0 10 
//-2 10 
//-5 9 
//-8 7 
//-8 4 
//-6 1 
//-2 0 

另一种方法还没有实践,不过感性理解上是正确的。对于一个点,可以通过余弦定理判断它和左右两个点形成的角是不是钝角,如果是钝角的话就可以向多边形内的方向进行扩展,也能得到合法的点。应该是对的吧。

\(T2\)
2023/2/22 模拟赛-小白菜博客
期望 \(DP\)……纯纯不会。
2023/2/22 模拟赛-小白菜博客
image

题解先放这,看看以后能不能看懂。

\(T3:\)
image

这个数据结构……过于逆天,还是放个题解先,看以后能不能懂。
image

\(T4:等你哈苏德\)
image

这个题考的主要是混合图欧拉回路的应用,关于混合图欧拉回路,可以参见这个。接下来讨论下这个题为什么是混合图欧拉回路的做法。

首先将题目抽象一下:如果一个 \([l,r]\) 的区间是黑色,就看作从 \(l\)\(r + 1\) 连了一条边,否则就是从 \(r + 1\)\(l\) 连一条边。如此,一个点被连入一条边,度加 \(1\),就相当于被黑色覆盖了,如果从它这里出了一条边,度减 \(1\),就相当于被白色覆盖了一次。如此,便将颜色的覆盖转化为了点的出入度之差。当每个点被白色覆盖的次数与被黑色覆盖的次数相等时,等价于图中有一条串了所有点的欧拉回路。

然而我们随意定向的边,可能导致有些点的出入度之差为奇数,我们将这些度数为奇数的点存到 \(a\),排序后将 \(a_i\)\(a_{i + 1}\) 相连。这可以满足一个区间内的黑白覆盖次数绝对值之差小于等于 \(1\),最后跑混合图欧拉回路即可。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6;
const int INF = 0x3f3f3f3f;
int id[MAXN + 5],n,m,tot,deg[MAXN + 5],node[MAXN + 5],cno,head[MAXN + 5],s,t,dis[MAXN + 5],cur[MAXN + 5],ans[MAXN + 5],cnt;
bool vis[MAXN + 5];
vector<int> lsh;
struct E{
	int l,r,w;
}e[MAXN + 5];
struct EDGE{
	int u,v,w,next;
}edge[MAXN + 5];
void ADD(int u,int v,int w){
	++tot;
	edge[tot].u = u;
	edge[tot].v = v;
	edge[tot].w = w;
	edge[tot].next = head[u];
	head[u] = tot;
}
void add(int u,int v,int w){
	ADD(u,v,w);
	ADD(v,u,0);
}
bool bfs(){
	queue<int> q;
	q.push(s);
	memset(dis,0,sizeof dis);
	dis[s] = 1;
	while(!q.empty()){
		int u = q.front();
		q.pop();
		for(int i = head[u]; i; i = edge[i].next){
			int v = edge[i].v;
			if(!dis[v] && edge[i].w > 0){
				dis[v] = dis[u] + 1;
				q.push(v);
			}
		}
	}
	if(dis[t])return 1;
	return 0;
}
int dfs(int u,int dist){
	if(u == t)return dist;
	for(int &i = cur[u]; i; i = edge[i].next){
		int v = edge[i].v;
		if(dis[v] == dis[u] + 1 && edge[i].w > 0){
			int di = dfs(v,min(edge[i].w,dist));
			if(di > 0){
				edge[i].w -= di;
				edge[i ^ 1].w += di; 
				return di;
			}
		}
	}
	return 0;
}
int dinic(){
	int an = 0;
	while(bfs()){
		for(int i = s; i <= t; i++){cur[i] = head[i];}
		while(int di = dfs(s,INF))an += di;
	}
	return an;
}
int main(){
	freopen("wait.in","r",stdin);
	freopen("wait.out","w",stdout);
	tot = 1;
	scanf("%d%d",&m,&n);
	for(int i = 1; i <= m; i++){
		scanf("%d%d%d",&e[i].l,&e[i].r,&e[i].w);
		e[i].r++;
		lsh.push_back(e[i].l);
		lsh.push_back(e[i].r);
	}
	sort(lsh.begin(),lsh.end());
	lsh.erase(unique(lsh.begin(),lsh.end()),lsh.end());
	for(int i = 1; i <= m; i++){
		e[i].l = lower_bound(lsh.begin(),lsh.end(),e[i].l) - lsh.begin() + 1;
		e[i].r = lower_bound(lsh.begin(),lsh.end(),e[i].r) - lsh.begin() + 1;
	}
	for(int i = 1; i <= m; i++){
		if(e[i].w == -1){
			add(e[i].l,e[i].r,1);
			ans[tot / 2] = 1;
			deg[e[i].l]++;
			deg[e[i].r]--;
			id[i] = tot;
		}
		else if(e[i].w == 1)deg[e[i].l]++,deg[e[i].r]--;
		else deg[e[i].r]++,deg[e[i].l]--; 
		node[++cno] = e[i].l,node[++cno] = e[i].r;
	}
	sort(node + 1,node + 1 + cno);
	for(int i = 1; i < cno; i += 2){
		if(node[i] == node[i + 1])continue;
		++deg[node[i]],--deg[node[i + 1]];
		add(node[i],node[i + 1],1);
	}
	s = 0,t = lsh.size() + 1;
	for(int i = 1; i <= lsh.size(); i++){
		if(deg[i] >= 0){
			add(s,i,deg[i] / 2);
			cnt += deg[i] / 2;
		}
		else{
			add(i,t,(-deg[i] / 2));
		}
	}
	int k;
	k = dinic();
	if(k < cnt){
		cout << "-1";
		return 0;
	}
	for(int i = 1; i <= m; i++){
		if(e[i].w == -1){
			cout << (edge[id[i]].w ^ 1) << " ";
		}
		else cout << e[i].w << " ";
	}
}
//4 1000000000
//1 9 -1
//2 6 -1
//1 8 -1
//1 7 -1