CF1292E Rin and The Unknown Flower 题解
IO 交互题 fflush(stdout)
害人不浅!!1
注意到如果我们发起询问 C
和 O
就可以花费 2 的代价知道整个串,不过代价过高,所以我们考虑减小点代价。
考虑发起询问 CO,CH,CC
,这样我们必然可以知道除了最后一位以外所有 C
的位置,然后类似的询问 HO,OO
,这样我们必然可以知道除了第一位以外所有 O
的位置(前面问过一次 CO
)。
考虑第二位至第 \(n-1\) 位,注意到此时里面不确定的位置必然都是 H
,因为如果有 C
或者 O
肯定已经被问出来了。
这样就只剩下第一位和第 \(n\) 位了,又第一位不会是 C
,最后一位不会是 O
,于是至多只有 4 种情况,问 3 次即可知道答案。
代价为 \(5\times\dfrac{1}{4}+3\times\dfrac{1}{n^2}\),易知该式在 \(n\ge5\) 时小于等于 1.4。
然后 \(n\ge4\),所以 \(n=4\) 还要另外想办法。下面大分类讨论预警,可以画个决策树理解。
注意到上面问了五个串 CO,CH,CC,HO,OO
,\(n=4\) 不行的关键在于后面 3 次是错代价过大,然而这些试错是必须的,所以只能减少前面的询问。
考虑先询问 CO,CH,CC,HO
,如果我们当前已经问出来了至少两个位置,那么剩下只有至多两个位置不确定且前三位必然不是 C
,最坏情况有六种可能,试五次错即可,代价 \(4\times\dfrac{1}{4}+5\times\dfrac{1}{16}=1.3125\)。
如果这些都没问出来,那么只有两种可能,一种是含有 OO
一种是含有 HH
,然后在决策树上发现这样问完后只需要问一次长度为 4 的串即可,没超 1.4,于是问一下 OO
。
如果有,说明只可能是 OOOO,OOOH,OOOC,OOHC,OOHH
这四种情况(剩余情况肯定前面都被问出来了),同时已知 OOOO
不用询问,如果有两个位置不确定必是 OOHC,OOHH
中一种,否则是 OOOH,OOOC
中一种,无论哪种代价都是 \(5\times\dfrac{1}{4}+\dfrac{1}{16}=1.3125\)。
否则中间两位必然是 HH
,第一位只能是 O,H
,最后一位只能是 C,H
,然而我们不能询问 3 次(否则代价为 \(1.4375\)),于是问一下 HHH
,这样可以确定这两位是不是 H
,如果不是那也只有一种情况,代价 \(5\times\dfrac{1}{4}+\dfrac{1}{9}\approx1.361<1.4\)。
做完了,我写代码的时候 \(n\ge5\) 写了 1k,\(n=4\) 写了 3k /fad
Code:
/*
========= Plozia =========
Author:Plozia
Problem:CF1292E Rin and The Unknown Flower
Date:2022/11/13
========= Plozia =========
*/
#include <bits/stdc++.h>
typedef long long LL;
#define Flu fflush(stdout)
#define rt return
const int MAXN = 50 + 5;
int n;
char str[MAXN], Next[6][2] = {{'H', 'H'}, {'H', 'O'}, {'O', 'H'}, {'O', 'O'}, {'H', 'C'}, {'O', 'C'}};
int Read()
{
int sum = 0, fh = 1; char ch = getchar();
for (; ch < '0' || ch > '9'; ch = getchar()) fh -= (ch == '-') << 1;
for (; ch >= '0' && ch <= '9'; ch = getchar()) sum = (sum << 3) + (sum << 1) + (ch ^ 48);
rt sum * fh;
}
void Solve2()
{
puts("? CC"); Flu; int k = Read(), cnt = 0;
for (int i = 1; i <= k; ++i) { ++cnt; int x = Read(); str[x] = str[x + 1] = 'C'; }
puts("? CO"); Flu;
k = Read(); for (int i = 1; i <= k; ++i) { ++cnt; int x = Read(); str[x] = 'C', str[x + 1] = 'O'; }
puts("? CH"); Flu;
k = Read(); for (int i = 1; i <= k; ++i) { ++cnt; int x = Read(); str[x] = 'C', str[x + 1] = 'H'; }
puts("? HO"); Flu;
k = Read(); for (int i = 1; i <= k; ++i) { ++cnt; int x = Read(); str[x] = 'H', str[x + 1] = 'O'; }
if (cnt > 0)
{
cnt = 0; for (int i = 1; i <= n; ++i) cnt += (str[i] == '?');
if (cnt == 0) { printf("! %c%c%c%c\n", str[1], str[2], str[3], str[4]); Flu; rt; }
if (cnt == 1)
{
if (str[1] == '?')
{
printf("? H%c%c%c\n", str[2], str[3], str[4]); Flu;
k = Read(); if (k) { Read(); printf("! H%c%c%c\n", str[2], str[3], str[4]); Flu; rt; }
printf("! O%c%c%c\n", str[2], str[3], str[4]); Flu; rt;
}
printf("? %c%c%cH\n", str[1], str[2], str[3]); Flu;
k = Read(); if (k) { Read(); printf("! %c%c%cH\n", str[1], str[2], str[3]); Flu; rt; }
printf("? %c%c%cO\n", str[1], str[2], str[3]); Flu;
k = Read(); if (k) { Read(); printf("! %c%c%cO\n", str[1], str[2], str[3]); Flu; rt; }
printf("! %c%c%cC\n", str[1], str[2], str[3]); Flu; rt;
}
if (str[1] == '?' && str[4] == '?')
{
for (int i = 0; i < 5; ++i)
{
printf("? %c%c%c%c\n", Next[i][0], str[2], str[3], Next[i][1]); Flu;
int k = Read(); if (k) { Read(); printf("! %c%c%c%c\n", Next[i][0], str[2], str[3], Next[i][1]); Flu; rt; }
}
printf("! O%c%cC\n", str[2], str[3]); Flu; rt;
}
if (str[1] == '?')
{
for (int i = 0; i < 3; ++i)
{
printf("? %c%c%c%c\n", Next[i][0], Next[i][1], str[3], str[4]); Flu;
int k = Read(); if (k) { Read(); printf("! %c%c%c%c\n", Next[i][0], Next[i][1], str[3], str[4]); Flu; rt; }
}
printf("! OO%c%c\n", str[3], str[4]); Flu; rt;
}
for (int i = 0; i < 5; ++i)
{
printf("? %c%c%c%c\n", str[1], str[2], Next[i][0], Next[i][1]); Flu;
int k = Read(); if (k) { Read(); printf("! %c%c%c%c\n", str[1], str[2], Next[i][0], Next[i][1]); Flu; rt; }
}
printf("! %c%cOC\n", str[1], str[2]); Flu; rt;
}
puts("? OO"); Flu; k = Read(); for (int i = 1; i <= k; ++i) { ++cnt; int x = Read(); str[x] = str[x + 1] = 'O'; }
if (cnt)
{
cnt = 0; for (int i = 1; i <= n; ++i) cnt += (str[i] == '?');
if (cnt == 0) { printf("! %c%c%c%c\n", str[1], str[2], str[3], str[4]); Flu; rt; }
if (cnt == 1)
{
puts("? OOOC"); Flu; int k = Read();
if (k) { Read(); puts("! OOOC"); Flu; rt; }
else { puts("! OOOH"); Flu; rt; }
}
puts("? OOHC"); Flu; int k = Read(); if (k) { Read(); puts("! OOHC"); Flu; rt; }
puts("! OOHH"); Flu; rt;
}
puts("? HHH"); Flu; k = Read(); for (int i = 1; i <= k; ++i) { int x = Read(); str[x] = str[x + 1] = str[x + 2] = 'H'; }
printf("! %cHH%c\n", (str[1] == '?') ? 'O' : str[1], (str[4] == '?') ? 'C' : str[4]); Flu; rt;
}
void Solve()
{
n = Read(); for (int i = 1; i <= n; ++i) str[i] = '?';
if (n == 4) { Solve2(); rt; } int k;
puts("? CO"); Flu; k = Read(); for (int i = 1; i <= k; ++i) { int x = Read(); str[x] = 'C', str[x + 1] = 'O'; }
puts("? CC"); Flu; k = Read(); for (int i = 1; i <= k; ++i) { int x = Read(); str[x] = str[x + 1] = 'C'; }
puts("? CH"); Flu; k = Read(); for (int i = 1; i <= k; ++i) { int x = Read(); str[x] = 'C', str[x + 1] = 'H'; }
puts("? HO"); Flu; k = Read(); for (int i = 1; i <= k; ++i) { int x = Read(); str[x] = 'H', str[x + 1] = 'O'; }
puts("? OO"); Flu; k = Read(); for (int i = 1; i <= k; ++i) { int x = Read(); str[x] = 'O', str[x + 1] = 'O'; }
for (int i = 2; i < n; ++i) if (str[i] == '?') str[i] = 'H';
for (int i = 0; i < 5; ++i)
{
if (i == 1 || i == 3) continue ;
printf("? %c", (str[1] == '?') ? Next[i][0] : str[1]);
for (int _ = 2; _ < n; ++_) printf("%c", str[_]);
printf("%c\n", (str[n] == '?') ? Next[i][1] : str[n]); Flu;
k = Read();
if (k)
{
Read();
printf("! %c", (str[1] == '?') ? Next[i][0] : str[1]);
for (int _ = 2; _ < n; ++_) printf("%c", str[_]);
printf("%c\n", (str[n] == '?') ? Next[i][1] : str[n]); Flu; rt;
}
}
printf("! %c", (str[1] == '?') ? 'O' : str[1]);
for (int _ = 2; _ < n; ++_) printf("%c", str[_]);
printf("%c\n", (str[n] == '?') ? 'C' : str[n]); Flu; rt;
}
int main()
{
int t = Read(); while (t--) { Solve(); if (Read() == 0) rt 0; } rt 0;
}