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

考场上一眼计算几何,直接毙掉不做。考完后发现很简单……
正解方法确实抽象……首先,把输入的整点分为 ,,,,这四种类型的点。考虑到只需输出 ,个点,相对来说不多。又因为是凸多边形,因此考虑按照点两个坐标的奇偶性配对,使得两点的中点为整点,输出即可。
点击查看代码
#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;
}
}
}
另一种方法还没有实践,不过感性理解上是正确的。对于一个点,可以通过余弦定理判断它和左右两个点形成的角是不是钝角,如果是钝角的话就可以向多边形内的方向进行扩展,也能得到合法的点。应该是对的吧。

期望 ……纯纯不会。


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

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


这个题考的主要是混合图欧拉回路的应用,关于混合图欧拉回路,可以参见这个。接下来讨论下这个题为什么是混合图欧拉回路的做法。
首先将题目抽象一下:如果一个 的区间是黑色,就看作从 向 连了一条边,否则就是从 向 连一条边。如此,一个点被连入一条边,度加 ,就相当于被黑色覆盖了,如果从它这里出了一条边,度减 ,就相当于被白色覆盖了一次。如此,便将颜色的覆盖转化为了点的出入度之差。当每个点被白色覆盖的次数与被黑色覆盖的次数相等时,等价于图中有一条串了所有点的欧拉回路。
然而我们随意定向的边,可能导致有些点的出入度之差为奇数,我们将这些度数为奇数的点存到 ,排序后将 与 相连。这可以满足一个区间内的黑白覆盖次数绝对值之差小于等于 ,最后跑混合图欧拉回路即可。
点击查看代码
#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 << " ";
}
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具