F - Lost Root Shows CodeForces - 1061F(交互+概率)

Lost Root

time limit per test 3 seconds

memory limit per test 256 megabytes

Problem Description

The graph is called tree if it is connected and has no cycles. Suppose the tree is rooted at some vertex. Then tree is called to be perfect kk-ary tree if each vertex is either a leaf (has no children) or has exactly kk children. Also, in perfect kk-ary tree all leafs must have same depth.

For example, the picture below illustrates perfect binary tree with 1515 vertices:

There is a perfect kk-ary tree with nn nodes. The nodes are labeled with distinct integers from 11 to nn, however you don‘t know how nodes are labelled. Still, you want to find the label of the root of the tree.

You are allowed to make at most 60⋅n60⋅n queries of the following type:

  • "? aa bb cc", the query returns "Yes" if node with label bb lies on the path from aa to cc and "No" otherwise.

Both aa and cc are considered to be lying on the path from aa to cc.

When you are ready to report the root of the tree, print

  • "! ss", where ss is the label of the root of the tree.

It is possible to report the root only once and this query is not counted towards limit of 60⋅n60⋅n queries.

Interaction

The first line of the standard input stream contains two integers nn and kk (3≤n≤15003≤n≤1500, 2≤k<n2≤k<n) — the number of nodes in the tree and the value of kk.

It is guaranteed that nn is such that the tree forms a perfect kk-ary tree.

You can ask at most 60⋅n60⋅n queries. To ask a query, print a line of form "? aa bb cc", where 1≤a,b,c≤n1≤a,b,c≤n. After that you should read a single line containing "Yes" or "No" depending on the answer of the query.

The tree is fixed for each test and it doesn‘t depend on your queries.

When you are ready to print the answer, print a line of the form "! ss", where ss is the label of the root vertex and then terminate your program.

After printing each query do not forget to print end of line and flush the output. Otherwise you may get Idleness limit exceeded. To do this, use:

  • fflush(stdout) or cout.flush() in C++;
  • System.out.flush() in Java;
  • flush(output) in Pascal;
  • stdout.flush() in Python;
  • See documentation for other languages.

In case your program will make more than 60⋅n60⋅n queries, but in other aspects would follow the interaction protocol and terminate coorectly, it will get verdict «Wrong Answer».

Hacks

To hack the solution use the following test format:

The first line should contain integers nn and kk (3≤n≤15003≤n≤1500, 2≤k≤15002≤k≤1500) — the number of vertices and the kk parameter of the tree.

Of course, the value of nn must correspond to the size of the valid kk-ary tree of some depth.

The second line should contain a1,a2,…,ana1,a2,…,an (1≤ai≤n1≤ai≤n) — the labels of the tree in the natural order, all labels must be distinct.

Let‘s call the following ordering of the tree vertices to be natural: first the root of the tree goes, then go all vertices on depth of one edge from root, ordered from left to right, then go all vertices on depth of two edges from root, ordered from left to right, and so on until the maximum depth.

This way, the a1a1 is the answer for the hack.

Example

Input

Copy

3 2

No

Yes

Output

Copy

? 1 3 2

? 1 2 3

! 2

Note

The tree in the example is as follows:

The input and output for example illustrate possible interaction on that test (empty lines are inserted only for clarity).

The hack corresponding to the example would look like:

3 22 3 1

Solution:

首先给出一个n节点的k叉树,1-n被乱贴在节点上,每次能询问 x,y,z(y是否再x,z路径上在就交互Yes,不在就No)问能否再 60*n次询问内,找到root具体贴上什么意思是我们要在yes/no中挖掘出有利于找出根的信息,考虑yes,说明 某个数在某个路径上,就是在k叉树上不小心 根 包含在这路径上,返回yes,也得不到是否就是根,意思是返回yes仅仅代表它存在于路径中,我们可能要借助它存在于路径的次数得出结论。出现次数究竟能干什么呢,如果某个路径包含根,肯定分在两边,我们想尽可能两边对称才好办利用等值可以知道中点,那什么时候中点必然是根呢?很难办,如果是叶子节点的话就是路径长度为2h-1的时候了,叶子节点怎么求呢?假设y是叶子节点的话肯定没右路径可以包含它~,利用no就行了,只要 i x y(x!=y,i∈[1,n]) 一直是no即叶子节点。知道两个叶子节点就可以反求根了,复杂度的话,由于叶子节点每层都会增大k倍(k>=2)那至少也得有1/2的叶子节点,而找到两个不同的叶子节点后,只要其位于两边,路径肯定是2*h+1概率也是1/2,大概 15* O(n)就找到两个叶子节点了,剩下概率很高就是了(我也不是很清楚。。。=_=!)

接下来就是代码啦~
 1 #include<iostream>
 2 #include<algorithm>
 3 #include<string>
 4 #include<cmath>
 5
 6 using namespace std;
 7
 8 int n, k, h;
 9 string ts;
10
11 void query(int x, int y, int z) {
12     cout << "? " << x << " " << y << " " << z << endl;
13 }
14
15 int getleaf() {
16     while (1) {
17         int x = rand() % n + 1,y;
18         while (y = rand() % n + 1) if (y != x) break;
19         int f = 0;
20         for (int i = 1; i <= n; ++i) {
21             if (i == x || i == y) continue;
22             query(i, x, y);
23             cin >> ts;
24             if (ts == "Yes") { f = 1; break; }
25         }
26         if (f == 0) return x;
27     }
28 }
29
30 int cnt_path_num(int x,int y) {
31     int cnt = 0;
32     for (int i = 1; i <= n; ++i) {
33         query( x, i, y);
34         cin >> ts;
35         if (ts == "Yes") ++cnt;
36     }
37     //printf("x,y_path %d %d ,cnt: %d\n", x, y, cnt);
38     return cnt;
39 }
40
41 int get_root(int x, int y) {
42     for (int i = 1; i <= n; ++i) {
43         query( x, i, y);
44         cin >> ts;
45         if (ts == "Yes") {
46             int l = cnt_path_num(x, i);
47             int r = cnt_path_num(i, y);
48             //printf("%d-> %d <-%d,%d,%d\n", x, i, y, l, r);
49             if (l == r && l == h) return i;
50         }
51     }
52     return 0;
53 }
54
55 int main()
56 {
57     srand(1e9+7);
58     cin >> n >> k;
59     for (int i = 0,t=1; i <= n; t *= k, i += t, ++h);
60     int x = getleaf();
61     //printf("leaf %d\n", x);
62     while (1) {
63         int y = getleaf();
64         //printf("leaf %d\n", y);
65         if (x == y) continue;
66         if (cnt_path_num(x, y) != 2 * h - 1) continue;
67         //puts("来啦老弟\n");
68         int tmp = get_root(x, y);
69         if (tmp == 0) continue;
70         return cout << "! " << tmp << endl, 0;
71     }
72     return 0;
73 }

原文地址:https://www.cnblogs.com/SayGB/p/10398540.html

时间: 2024-08-25 18:56:58

F - Lost Root Shows CodeForces - 1061F(交互+概率)的相关文章

codeforces 148D 【概率dp】

题目链接: codeforces 148D Bag of mice 题意:一个包里面有w只白老鼠和b只黑老鼠,公主与龙依次从包中拿老鼠,每次取一只,当龙拿时还会从包中溜走一只,先拿到老鼠的获胜,当背包中没老鼠时且之前没人拿到白老鼠则龙获胜,问公主获胜的概率是多少. 题解: 设dp[i][j]为背包中有i只白老鼠j只黑老鼠时公主获胜的概率 则公主获胜的情况分成三种: 1.直接拿到白老鼠 p1=i/(i+j) 2.公主拿到黑老鼠,龙拿到黑老鼠,逃跑一只黑老鼠 p2=(j/(i+j)) ((j-1)/

Codeforces 16E Fish 概率DP

这一场好水啊..这题算是比较简单的概率DP了吧,外加一点状压. dp[sta] = sigma (dp[sta|(1<<i)]*val[j][i]/( (ans+1)*ans/2 ) ),(i为sta已被吃掉的,j为存活的,ans为存活的个数). 之所以要除( (ans+1)*ans/2 ),是因为在ans+1条鱼中一共有这些对,且这些对等概率. #include <algorithm> #include <iostream> #include <cstring&

Codeforces 623D [Amazing概率题]

很有趣的一道题吖! 做法:贪心+迭代 Sigma(i*(pr[i]-pr[i-1])))=n-sigma(pr[i]), 所以我们贪心地是pr[i]尽可能大. 也就是让pr[i]/pr[i-1]尽可能大. 这种类型的贪心,和17EC-Final的那个最小化方差的题挺相似的. #include <iostream> #include <algorithm> #include <cstdio> #include <vector> #include <cma

F - Restoring the Expression CodeForces - 898F

字符串hash:  base设置为10 枚举'='可能出现的位置,从1/2处开始到大概1/3处结束,当然大概的1/3不用计算,直接到最后就行,因为本题必然有解,输出直接结束即可. 根据'='号位置,'+'最多有四种位置,因为 等式的和位数确定,有进位和不进位,左和右,最多2X2,然后剪掉j的非法位置(这里没计算除了len=3以外的j有无非法位置的可能,剪了再说) 比较需要注意的地方是等式中非个位数字不能以'0'开头,开始只以为不以'0'开头即可,WA在了 1+0=0 ,改了j后又WA了0+0=0

F - Make It Equal CodeForces - 1065C

题目大意:有n座塔,塔高h[i],每次给定高度H对他们进行削切,要求每次削掉的所有格子数不能超过k个,输出最少削几次才能使所有塔的高度相同. 思路一:差分+贪心 对于每一个高度h,用一个数组让1~h的数,每一个都加一.用差分求一下后缀和可以完成. AC code: #include<bits/stdc++.h> using namespace std; typedef long long ll; const ll N=2E5+7; ll arr[N]; int main() { ll n,k;

F - Link/Cut Tree CodeForces - 614A(水题)

Programmer Rostislav got seriously interested in the Link/Cut Tree data structure, which is based on Splay trees. Specifically, he is now studying the expose procedure. Unfortunately, Rostislav is unable to understand the definition of this procedure

Educational Codeforces Round 76 F 折半枚举

Educational Codeforces Round 76 F 折半枚举 https://codeforces.com/contest/1257/problem/F 题意: 数组a,找到一个x使得a中每一个元素异或x后"二进制中1的个数"相同. 数组长度100,数字大小2^30. 思路: 折半枚举答案X,如分为X前15位和后15位.之后我们再枚举期望的"相同个数"是多少,通过hash看看能不能满足就好了. 代码: #include <bits/stdc++

Codeforces 455C Civilization(并查集+dfs)

题目链接:Codeforces 455C Civilization 题目大意:给定N,M和Q,N表示有N个城市,M条已经修好的路,修好的路是不能改变的,然后是Q次操作,操作分为两种,一种是查询城市x所在的联通集合中,最长的路为多长.二是连接两个联通集合,采用联通之后最长路最短的方案. 解题思路:因为一开时的图是不可以改变的,所以一开始用dfs处理出各个联通集合,并且记录住最大值,然后就是Q次操作,用并查集维护,注意因为联通的时候要采用最长路径最短的方案,所以s的转移方程变为s = max(s,

[Codeforces Round #146 (Div. 1) B]Let&#39;s Play Osu!(期望Dp)

Description You're playing a game called Osu! Here's a simplified version of it. There are n clicks in a game. For each click there are two outcomes: correct or bad. Let us denote correct as "O", bad as "X", then the whole play can be