其他分享
首页 > 其他分享> > #24 CF1438F

#24 CF1438F

作者:互联网

Olha and Igor

题目描述

点此看题

解法

自己想了一个 \(O(n^2)\) 的做法,好像也要基于 \(\tt lca\) 的出现频率这东西(多少沾点边了

考虑询问 \((u,v,w)\) 的另一种意义:在树上找到点 \(x\),使得 \(d(u,x)+d(v,x)+d(w,x)\) 最小。

发现如果我们随机三个不同的点问一次 \((u,v,w)\),考虑分析得到的结果:

那么我们可以随机 \(420\) 次,认为出现频率最大的两个点就是根的左右儿子。设得到了 \(x,y\),那么我们枚举根,如果询问 \((x,y,i)\) 得到 \(i\),那么 \(i\) 就是真正的根,发现最坏情况下询问次数 \(n+420\)

#include <cstdio>
#include <random>
#include <algorithm>
using namespace std;
const int M = 1000005;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,h,a[M],p[M];
int ask(int u,int v,int w)
{
	printf("? %d %d %d\n",u,v,w);
	fflush(stdout);
	return read();
}
signed main()
{
	h=read();n=(1<<h)-1;
	mt19937 z(114514);
	for(int i=0;i<420;i++)
	{
		int u=z()%n+1,v=z()%n+1,w=z()%n+1;
		while(u==v) v=z()%n+1;
		while(u==w || v==w) w=z()%n+1;
		a[ask(u,v,w)]++;
	}
	for(int i=1;i<=n;i++) p[i]=i;
	sort(p+1,p+1+n,[&](int i,int j)
	{return a[i]>a[j];});
	int x=p[1],y=p[2];
	for(int i=1;i<=n;i++)
		if(i!=x && i!=y && ask(x,y,i)==i)
		{
			printf("! %d\n",i);
			fflush(stdout);
			return 0;
		}
}

标签:24,左子,CF1438F,一个点,int,右子,420,include
来源: https://www.cnblogs.com/C202044zxy/p/16335876.html