zoukankan      html  css  js  c++  java
  • 【CF1438F】Olha and Igor

    题目

    题目链接:https://codeforces.com/problemset/problem/1438/F

    这是一道交互题
    给定一个高度为(h)完美的二叉树(恰好有(2^h-1)个节点)
    你可以进行以下询问至多(n+420)

    • 选择三个互不相同的点(u,v,w),你需要保证(1leq u,v,wleq n)
    • 交互库会返回当以(w)为根时(u)(v)的lca。

    你需要向交互库回答根的编号
    (3leq hleq 18)

    思路

    这种题这辈子也做不出来的。
    考虑询问 ((x,y,z)) 的本质,其实就是返回树上距离 (x,y,z) 三点距离之和最小的点。显然有且仅有一个这样的点。
    对于一个子树大小为 (s) 的点(完全二叉树左右子树大小一样),满足该点到 (x,y,z) 三个点距离最小的方案数为 (s^2(n-2s-1))。其中 (n) 是树大小,也就是 (2^h-1)
    不难发现这个点是根节点两个儿子时,方案数最多。
    那么考虑随机 (420) 次点对,然后统计每一个点被返回的次数,有极大概率出现次数最多的两个点就是根的儿子。CF 上题解也没有证明 (420) 次随机后正确的期望。所以就假装对的吧。
    最后枚举所有点,与得到出现次数最多的两个点询问一遍,判断是不是根即可。
    时间复杂度 (O(2^h))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=(1<<18)+10;
    int n,x,cnt[N],s1,s2;
    
    int random(int l=1,int r=1e9)
    {
    	return ((rand()<<15)|rand())%(r-l+1)+l;
    }
    
    int main()
    {
    	srand(1023);
    	scanf("%d",&n);
    	n=(1<<n)-1;
    	for (int i=1;i<=420;i++)
    	{
    		int a=random(1,n),b=random(1,n),c=random(1,n);
    		while (a==b || b==c || a==c) a=random(1,n),b=random(1,n),c=random(1,n);
    		printf("? %d %d %d
    ",a,b,c);
    		fflush(stdout);
    		scanf("%d",&x);
    		cnt[x]++;
    	}
    	for (int i=1;i<=n;i++)
    		if (cnt[i]>cnt[s1]) s2=s1,s1=i; else
    		if (cnt[i]>cnt[s2]) s2=i;
    	for (int i=1;i<=n;i++)
    	{
    		if (i==s1 || i==s2) continue;
    		printf("? %d %d %d
    ",s1,s2,i);
    		fflush(stdout);
    		scanf("%d",&x);
    		if (x==i) return printf("! %d
    ",i),0;	
    	}
    	return 0;
    }
    
  • 相关阅读:
    NOIP201208同余方程
    NOIP模拟赛 最佳组合
    NOIP模拟赛 拓展
    CF1253E Antenna Coverage(DP)
    LOJ6033「雅礼集训 2017 Day2」棋盘游戏 (博弈论,二分图,匈牙利算法)
    CF582E Boolean Function(DP,状态压缩,FMT)
    CF750G New Year and Binary Tree Paths(DP)
    Codeforces Round 596 题解
    AGC008E Next or Nextnext(组合计数,神奇思路)
    ARC082E ConvexScore(神奇思路)
  • 原文地址:https://www.cnblogs.com/stoorz/p/14602080.html
Copyright © 2011-2022 走看看