Codeforces Round 951 (Div. 2) F. Kostyanych‘s Theorem(思维题 交互好题)

2024-06-08 03:36

本文主要是介绍Codeforces Round 951 (Div. 2) F. Kostyanych‘s Theorem(思维题 交互好题),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目

交互题,n(n<=1e5)个点的完全图,无向的,初始恰好删了n-2条边

每次询问可以输入一个d:? d

交互器会输出一个当前度>=d的点v,

如果有多个这样的点,输出度最小的,如果还有多个,输出点号最小的

还会输出一个和这个点v当前没有连边的点x,如果x有多个,也输出点号最小的x

如果x不存在,输出x=0

然后交互器会把v这个点和当前连的所有边都删了,

如果没有找到这样的v,交互器输出0 0

最多n次询问后,你需要在「原图」中找到一条哈密顿路径(即一条路径恰访问每个点一次)

按顺序输出哈密顿路径

思路来源

Starsilk Cerulean 稲葉廻

题解

首先要想到问n-2,

问小于n-2肯定是不行的,这样你移除一个点,再也得不到它的信息

但是你只知道它和其中一个点不连接,不知道它另一个不连接的是谁,这样会缺信息

而一直问n-1显然肯定不行,这样会导致剩下的删边越来越多,最后剩下一堆小于n-2的

所以说就问n-2,根据交互器返回的第二维是不是0,

判断当前是n-2还是n-1,n-2时还能知道唯一不连接的是哪个

递归,数学归纳法思想,让剩下来的n个点的图还满足最多去掉n-2条边这个条件

1. 如果问出来的是n-2,显然删掉这个点的子图还满足这个条件,递归子图

2. 如果问出来的是n-1,n-1可以和子图内的点任意连,插入到任何地方,

再选取一个度数最小的点,去掉这两个点后又可以继续递归子图

也就是说,要么一次用到一条删边机会,要么两次用到>=两条删边机会,

使得剩下的x个点图余下的被删掉边的条数<=x-2
 

严格边数证明可以参考cf,这里可以感性理解一下图的密度(边平均度)

证明完边数之后,就是维护一个双端队列,

1. 不超过2个点,又没有边,直接放即可

2. n-2个点的,只有一条边不能连,判断一下不能和队首连就放到队尾,反之亦然

3. n-1个点的充当媒介,连接当前队尾和当前度最小的点

代码

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef pair<int,int> P;
#define fi first
#define se second
#define pb push_back
#define dbg(x) cerr<<(#x)<<":"<<x<<" ";
#define dbg2(x) cerr<<(#x)<<":"<<x<<endl;
#define SZ(a) (int)(a.size())
#define sci(a) scanf("%d",&(a))
#define pt(a) printf("%d",a);
#define pte(a) printf("%d\n",a)
#define ptlle(a) printf("%lld\n",a)
#define debug(...) fprintf(stderr, __VA_ARGS__)
using namespace std;
typedef long long ll;
deque<int>q;
int t,n;
P ask(int d){printf("? %d\n",d);fflush(stdout);int x,y;scanf("%d %d",&x,&y);return P(x,y);
}
void sol(int n){if(n<=2){rep(i,1,n){q.push_back(ask(0).fi);}return;}auto [x,y]=ask(n-2);// 要么一次用到一条删边机会,要么两次用到>=两条删边机会,保持图密度不降if(y){sol(n-1);if(q.front()==y)q.push_back(x);else q.push_front(x);}else{auto [y,z]=ask(0);sol(n-2);q.push_back(x);//x都能连q.push_back(y);}
}
void out(){printf("!");while(!q.empty()){int x=q.front();q.pop_front();printf(" %d",x);}printf("\n");fflush(stdout);
}
int main(){sci(t);while(t--){sci(n);q.clear();sol(n);out();}return 0;
}

这篇关于Codeforces Round 951 (Div. 2) F. Kostyanych‘s Theorem(思维题 交互好题)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1041107

相关文章

好题——hdu2522(小数问题:求1/n的第一个循环节)

好喜欢这题,第一次做小数问题,一开始真心没思路,然后参考了网上的一些资料。 知识点***********************************无限不循环小数即无理数,不能写作两整数之比*****************************(一开始没想到,小学没学好) 此题1/n肯定是一个有限循环小数,了解这些后就能做此题了。 按照除法的机制,用一个函数表示出来就可以了,代码如下

Codeforces Round #240 (Div. 2) E分治算法探究1

Codeforces Round #240 (Div. 2) E  http://codeforces.com/contest/415/problem/E 2^n个数,每次操作将其分成2^q份,对于每一份内部的数进行翻转(逆序),每次操作完后输出操作后新序列的逆序对数。 图一:  划分子问题。 图二: 分而治之,=>  合并 。 图三: 回溯:

Codeforces Round #261 (Div. 2)小记

A  XX注意最后输出满足条件,我也不知道为什么写的这么长。 #define X first#define Y secondvector<pair<int , int> > a ;int can(pair<int , int> c){return -1000 <= c.X && c.X <= 1000&& -1000 <= c.Y && c.Y <= 1000 ;}int m

Codeforces Beta Round #47 C凸包 (最终写法)

题意慢慢看。 typedef long long LL ;int cmp(double x){if(fabs(x) < 1e-8) return 0 ;return x > 0 ? 1 : -1 ;}struct point{double x , y ;point(){}point(double _x , double _y):x(_x) , y(_y){}point op

Codeforces Round #113 (Div. 2) B 判断多边形是否在凸包内

题目点击打开链接 凸多边形A, 多边形B, 判断B是否严格在A内。  注意AB有重点 。  将A,B上的点合在一起求凸包,如果凸包上的点是B的某个点,则B肯定不在A内。 或者说B上的某点在凸包的边上则也说明B不严格在A里面。 这个处理有个巧妙的方法,只需在求凸包的时候, <=  改成< 也就是说凸包一条边上的所有点都重复点都记录在凸包里面了。 另外不能去重点。 int

Codeforces 482B 线段树

求是否存在这样的n个数; m次操作,每次操作就是三个数 l ,r,val          a[l] & a[l+1] &......&a[r] = val 就是区间l---r上的与的值为val 。 也就是意味着区间[L , R] 每个数要执行 | val 操作  最后判断  a[l] & a[l+1] &......&a[r] 是否= val import ja

uniapp设置微信小程序的交互反馈

链接:uni.showToast(OBJECT) | uni-app官网 (dcloud.net.cn) 设置操作成功的弹窗: title是我们弹窗提示的文字 showToast是我们在加载的时候进入就会弹出的提示。 2.设置失败的提示窗口和标签 icon:'error'是设置我们失败的logo 设置的文字上限是7个文字,如果需要设置的提示文字过长就需要设置icon并给

CSS实现DIV三角形

本文内容收集来自网络 #triangle-up {width: 0;height: 0;border-left: 50px solid transparent;border-right: 50px solid transparent;border-bottom: 100px solid red;} #triangle-down {width: 0;height: 0;bor

颠覆你的开发模式:敏捷思维带来的无限可能

敏捷软件开发作为现代软件工程的重要方法论,强调快速响应变化和持续交付价值。通过灵活的开发模式和高效的团队协作,敏捷方法在应对动态变化和不确定性方面表现出色。本文将结合学习和分析,探讨系统变化对敏捷开发的影响、业务与技术的对齐以及敏捷方法如何在产品开发过程中处理持续变化和迭代。 系统变化对敏捷软件开发的影响 在敏捷软件开发中,系统变化的管理至关重要。系统变化可以是需求的改变、技术的升级、

创建一个大的DIV,里面的包含两个DIV是可以自由移动

创建一个大的DIV,里面的包含两个DIV是可以自由移动 <body>         <div style="position: relative; background:#DDF8CF;line-height: 50px"> <div style="text-align: center; width: 100%;padding-top: 0px;"><h3>定&nbsp;位&nbsp;