首页 > 其他分享 >[THUPC 2024 决赛] 采矿

[THUPC 2024 决赛] 采矿

时间:2024-08-15 10:38:42浏览次数:17  
标签:决赛 putchar goal THUPC int 2024 msk 答案 include

思路很自然的一道交互,赛场上都没来得及细做 QwQ。

首先询问树形态的交互题有一个非常通用的思路:剥叶子。应用在这个题上来后你马上就会发现这是好的,因为在本题中叶子有一个关键性质:只有一条邻边操控,如果这条邻边往外指那么这个点的答案一定是 \(1\)。

你会发现一个点答案是 \(1\) 的条件非常苛刻:需要其所有邻边都往外指,假设每一次询问都是纯随机的,那么叶子的答案是 \(1\) 的会大致占半数,而其它的小于半数。

我们考虑精细化设计这个策略让其变成确定性的。这个就是神隐的技巧,我们为每条边设计一个长度为 \(T=50\),恰好有 \(\frac{T}{2}=25\) 个 \(1\) 的二进制数 \(msk_i\),当对应 \(msk_i\) 的第 \(j\) 为 \(1\) 时我们第 \(j\) 次询问中翻转边 \(i\)。

我们只需要让这些二进制数互不相同,两两不为互补,这样的话假设一个度数至少为二的点来说,其为 \(1\) 的询问至少是 \(msk_1\cap msk_2\) 或者 \(msk_1\cap \overline{msk_2}\) 类似的形式,由于取交的两个元素不相等,其二进制下 \(1\) 的个数小于一半。所以我们只需要看哪些点恰好 \(\frac{T}{2}\) 次答案为 \(1\) 这些点就是叶子。

接下来是为这个叶子找到父亲以及找到连接它们的边。找相邻的边直接看一下其为 \(1\) 的位置与那条边的 \(msk\) 符合就行了。找父亲看起来需要一定的技巧。我们考虑当叶子不为的答案 \(1\),其答案一定是父亲的答案加上 \(1\)。我们可以猜测如果一个点满足其一直是叶子的答案减一,那么其大概率唯一而且就是这个叶子的父亲。

为啥呢?因为一个不是父亲的点想通过度数伪装成父亲是很难的,我们的 \(msk_i\) 对于每条边每次询问都是均匀的,而每修改一条边,其相邻两个点的度数一定会变化。就算最极端的情况,设我们寻找答案为 \(goal\) 的父亲,一个点修改一次变成 \(goal\),再修改一次一定不是 \(goal\),再修改一次可能又变成 \(goal\)……而修改与否都是 \(\frac{1}{2}\) 随机发生的,次数奇偶性也是随机的。这样不是父亲的点答案 \(=goal\) 的概率再怎么也不会超过 \(\frac{1}{2}\),整体至多有 \(2^{-\frac{T}{2}}\) 的错误率。

再考虑时间复杂度的事情,有人说你这代码三重循环乘起来 \(O(n^2T)\) 爆炸了啊?怎么能过呢?

事实上我们暴力 check 一个点在所有合法询问中是否都有答案 \(=goal\),如果其不是真正的父亲,失败的概率会达到 \(\frac{1}{2}\),这样期望 check 常数次就会退出,期望复杂度 \(O(n^2)\) 可以通过。

注意剥完一个叶子的时候,需要修改所有的询问对应的答案。一种方法是给每个点每次询问维护一个点权,表示删去的点中有多少可以到达它,然后把上述的所有 \(1\) 改成对应点权。

代码内置交互库,添加 LOCAL 宏就可以启用。

#include <map>
#include <cstdio>
#include <random>
#include <vector>
#include <cassert>
#include <algorithm>
using namespace std;
typedef long long ll;
mt19937 rng(random_device{}());
int read(){
	char c=getchar();int x=0;
	while(c<48||c>57) c=getchar();
	do x=x*10+(c^48),c=getchar();
	while(c>=48&&c<=57);
	return x;
}
const int N=10003,T=50;
const ll MS=(1ll<<T)-1;
int n;
int eu[N],ev[N];ll msk[N];
int d[T][N],w[T][N],cnt[N];
namespace grader{
#define fi first
#define se second
	typedef pair<int,int> pii;
	pii e[N];
	void gen(){
		for(int i=1;i<n;++i){
			e[i].fi=rng()%i+1;
			e[i].se=i+1;
			if(rng()&1) swap(e[i].fi,e[i].se);
		}
		shuffle(e+1,e+n,rng);
		for(int i=1;i<n;++i) printf("(%d->%d) ",e[i].fi,e[i].se);
		putchar('\n');
	}
	vector<int> vec[N];
	int dfs(int u){
		int res=1;
		for(int v:vec[u]) res+=dfs(v);
		return res;
	}
	void ask(int x){
		putchar('?');putchar(' ');
		for(int i=1;i<n;++i)
			if(msk[i]>>x&1) putchar('1');
			else putchar('0');
		putchar('\n');fflush(stdout);
#ifdef LOCAL
		for(int i=1;i<n;++i)
			if(msk[i]>>x&1) vec[e[i].fi].emplace_back(e[i].se);
			else vec[e[i].se].emplace_back(e[i].fi);
		for(int i=1;i<=n;++i) d[x][i]=dfs(i);
		for(int i=1;i<=n;++i) vec[i].clear();
#else
		for(int i=1;i<=n;++i) d[x][i]=read();
#endif
	}
	void check(){
		for(int i=1;i<n;++i) assert(eu[i]==e[i].fi&&ev[i]==e[i].se);
	}
#undef fi
#undef se
}
map<ll,int> mp;
ll gen(){
	int a[T];
	for(int i=0;i<T;++i) a[i]=2*i<T;
	shuffle(a,a+T,rng);
	ll cur=0;
	for(int i=0;i<T;++i) cur=cur<<1|a[i];
	return cur;
}
bool del[N];
int main(){
	n=read();
#ifdef LOCAL
	grader::gen();
#endif
	for(int i=1;i<n;++i){
		ll x=gen();
		while(mp.find(x)!=mp.end()) x=gen();
		mp.emplace(x,i);mp.emplace(MS^x,-i);msk[i]=x;
	}
	for(int t=0;t<T;++t){
		grader::ask(t);
		for(int i=1;i<=n;++i) w[t][i]=1,cnt[i]+=(d[t][i]==1);
	}
	for(int it=1;it<n;++it){
		int x,y;
		for(int i=1;i<=n;++i) 
			if(!del[i]&&cnt[i]==(T>>1)){x=i;break;}
		ll cur=0;
		for(int t=0;t<T;++t)
			if(d[t][x]==w[t][x]) cur|=(1ll<<t);
		for(y=1;y<=n;++y){
			if(del[y]) continue;
			bool fl=0;
			for(int t=0;t<T;++t){
				if(cur>>t&1) continue;
				if(d[t][x]==d[t][y]+w[t][x]) continue;
				fl=1;break;
			}
			if(fl) continue;
			break;
		}
		del[x]=1;cnt[y]=0;
		for(int t=0;t<T;++t){
			if(cur>>t&1) w[t][y]+=w[t][x];
			cnt[y]+=(d[t][y]==w[t][y]);
		}
		int ps=mp[cur];
		if(ps>0) eu[ps]=y,ev[ps]=x;
		else eu[-ps]=x,ev[-ps]=y;
	}
#ifdef LOCAL
	grader::check();
#endif
	putchar('!');
	for(int i=1;i<n;++i) printf(" %d %d",eu[i],ev[i]);
	putchar('\n');fflush(stdout);
	return 0;
}

标签:决赛,putchar,goal,THUPC,int,2024,msk,答案,include
From: https://www.cnblogs.com/yyyyxh/p/18360334/thupc_mine

相关文章

  • 聚众力·链未来 | 2024 FISCO BCOS认证合作伙伴
    为助力区块链技术成为数字经济高质量发展的关键引擎,让合作伙伴成为国产开源联盟链发展的坚实力量,金链盟正式启动2024年FISCOBCOS认证合作伙伴计划,面向社区招募产业应用合作伙伴、人才培育合作伙伴、生态发展合作伙伴。 产业应用合作伙伴聚焦高价值区块链技术应用场景,具备可......
  • 正版开源2024年最新微短剧系统-uniApp-微信小程序源码开源源码搭建部署,小程序端+源码
    系统介绍:短剧小程序是近年来兴起的一种新兴网络文艺样态,主要在小程序或社交平台上播放。这类短剧通常契合移动端的播放习惯,以竖屏拍摄为主,每集时长较短,但剧情紧凑,通过反转与冲突吸引观众,进而推动付费观看。一、技术框架开发短剧小程序可以选择以下技术框架:前端框架:可以使......
  • 2024表达式求值
    P06330.表达式求值Description一个数学表达式由下列元素组成:左括号,右括号,加号,减号,乘号,正号,负号,整数(无前导0)。给出一个长度不超过100的数学表达式,求它的值,要求考虑括号和乘法的优先级,计算过程中的临时值的绝对值保证不会超过整数范围。给出的表达式保证合法以及符合人的书写习......
  • 禅道 未授权登录复现(QVD-2024-15263)
    侵权声明本文章中的所有内容(包括但不限于文字、图像和其他媒体)仅供教育和参考目的。如果在本文章中使用了任何受版权保护的材料,我们满怀敬意地承认该内容的版权归原作者所有。如果您是版权持有人,并且认为您的作品被侵犯,请通过以下方式与我们联系:[[email protected]]。我们将在确......
  • 2024.8.14 总结(集训)
    依然是TQX来讲字符串。/bx/bx/bx属于是两个上午速通字符串里一些重要的内容。上课时只有manacher和PAM是我有点听懂了的。于是下午看TQX的博客学了PAM,看之前看过的博客复习了下SAM,给why讲了些、和他讨论了PAM,AC了洛谷上的PAM板子,看TQX的PPT学了manache......
  • 2024华为OD机试真题-启动多任务排序(C++/Python)-C卷D卷-200分
    2024华为OD机试题库目录(Python、C++)-(C卷+D卷)-CSDN博客目录题目描述输入描述输出描述用例1题目解析代码c++python题目描述一个应用启动时,会有多个初始化任务需要执行,并且任务之间有依赖关系,例如A任务依赖B任务,那么必须在B任务执行完成之后,才能开始执行A任务。......
  • 2024.8.14 test
    A一棵树,你每天可以选择不超过\(m\)个祖先都被选择的点,问最少多少天选完。\(n\le10^5\)。考虑贪心,每次选出子树深度最大的\(m\)个点或子树大小最大的\(m\)个点都是对的。B一棵树\(n\le5e5\),选若干出来,对于每个点,如果其儿子有选,那么不能被选,否则其有\(p_u\)概率被选......
  • 2024版,一键安装永久激活!
    2024版,一键安装永久激活!https://mp.weixin.qq.com/s?__biz=MzkxMzEyNTA2Nw==&mid=2247504674&idx=1&sn=6402cfd91b92f85e28a282fe10216aea&chksm=c100e886f67761904f3eab4607504da67c7342d29cb6ae4374a9f9b4b459d237f1bee0095510&mpshare=1&scene=23&sr......
  • 河南萌新联赛2024第(五)场:信息工程大学
    河南萌新联赛2024第(五)场:信息工程大学前言有点水这场,原题和板子貌似有点多。。A-日历游戏_河南萌新联赛2024第(五)场:信息工程大学(nowcoder.com)思路首先不看年份的话,显然\(8/1\)败,\(7/31\)胜,\(7/30\)败,\(7/29\)胜,\(\dots\),以此类推,就能发现一个\((m+d)\bmod2=0\)\((m......
  • [考试记录] 2024.8.14 csp-s模拟赛20
    [考试记录]2024.8.13csp-s模拟赛2090+39+0+0还是太......