Address
Solution
第一次做交互题。
题意大概是给定一个未知的,由 A 、 B 、 X 、 Y 构成的长度为
N
N
N 的字符串
S
S
S ,每次可以给出一个长度不超过
4
N
4N
4N 的字符串
T
T
T ,查询既是
T
T
T 的子串又是
S
S
S 的前缀的最长字符串的长度。使用不超过
N
+
2
N+2
N+2 次查询,还原出字符串
S
S
S 。
S
S
S 的第一个字符不会出现多次。
(1)求
S
S
S 的第一个字符。
先查询串 AB ,如果查询结果不为
0
0
0 ,则
S
[
1
]
S[1]
S[1] 为 A 或 B ,然后再查询串 A ,如果查询结果不为
0
0
0 则
S
[
1
]
S[1]
S[1] 为 A 否则为 B 。如果查询串 AB 的结果为
0
0
0 则
S
[
1
]
S[1]
S[1] 为 X 或 Y 。同样继续查询 X 进行判断。
操作数为
2
2
2 。
(2)已知
S
[
1...
i
]
S[1...i]
S[1...i] ,求
S
[
1...
i
+
1
]
S[1...i+1]
S[1...i+1] (
i
<
N
−
1
i<N-1
i<N−1 )。
即确定
S
[
i
+
1
]
S[i+1]
S[i+1] 。我们会发现,如果暴力判断需要
2
2
2 次操作,下面需要使用一种只使用
1
1
1 次操作的方法。
显然,只使用
1
1
1 次操作的关键是要通过查询的结果把三种字符区分开。
构造字符串(以
S
[
1
]
=
′
Y
′
S[1]='Y'
S[1]=′Y′ 为例):
S
[
1...
i
]
+
′
A
′
+
′
A
′
+
S
[
1...
i
]
+
′
A
′
+
′
B
′
+
S
[
1...
i
]
+
′
A
′
+
′
C
′
+
S
[
1..
i
]
+
′
B
′
S[1...i]+'A'+'A'+S[1...i]+'A'+'B'+S[1...i]+'A'+'C'+S[1..i]+'B'
S[1...i]+′A′+′A′+S[1...i]+′A′+′B′+S[1...i]+′A′+′C′+S[1..i]+′B′
长度最多为
4
N
−
1
4N-1
4N−1 。
易得,如果
S
[
i
+
1
]
=
′
A
′
S[i+1]='A'
S[i+1]=′A′ 则查询结果为
i
+
2
i+2
i+2 ,如果
S
[
i
+
1
]
=
′
B
′
S[i+1]='B'
S[i+1]=′B′ 则查询结果为
i
+
1
i+1
i+1 ,否则为
i
i
i 。
S
[
1
]
S[1]
S[1] 为其他字符时同理。
总操作次数
N
−
2
N-2
N−2 。
(3)求
S
[
N
]
S[N]
S[N] 。
暴力枚举。只需要枚举除
S
[
1
]
S[1]
S[1] 之外的两个字符。
当然和求 S[1] 一样也可以
操作次数
2
2
2 。
这样,总操作次数就是
N
+
2
N+2
N+2 。
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include "combo.h"
#define For(i, a, b) for (i = a; i <= b; i++)
const char ch[] = {'A', 'B', 'X', 'Y'};
std::string add(std::string s, int l, int r)
{
int i;
For (i, l, r) s.push_back(ch[i]);
return s;
}
std::string dda(std::string s, int l, int r)
{
int i; std::string res = "";
For (i, l, r) res += s, res.push_back(ch[i]);
return res;
}
char inters(int x, int y)
{
int i, pos = -1;
For (i, 1, y)
{
pos++;
if (pos == x) pos++;
}
return ch[pos];
}
std::string guess_sequence(int N)
{
int i, firs, l = 0, r = 3;
std::string st;
For (i, 0, 1)
{
int mid = l + r >> 1;
if (press(add(st, l, mid))) r = mid;
else l = mid + 1;
}
firs = l; st.push_back(ch[l]);
if (N == 1) return st;
For (i, 1, N - 2)
{
int tmp = press(st + inters(firs, 1) + inters(firs, 1)
+ st + inters(firs, 1) + inters(firs, 2)
+ st + inters(firs, 1) + inters(firs, 3)
+ st + inters(firs, 2));
if (tmp == i + 2) st.push_back(inters(firs, 1));
else if (tmp == i + 1) st.push_back(inters(firs, 2));
else st.push_back(inters(firs, 3));
}
l = 0; r = 3;
For (i, 0, 1)
{
int mid = l + r >> 1;
if (press(dda(st, l, mid)) == N) r = mid;
else l = mid + 1;
}
st.push_back(ch[l]);
return st;
}