咋提杂题

The 1st Universal Cup. Stage 15: Hangzhou

A. Turn on the Light 2025-3-31

交互二分题

  1. 所有灯泡默认是暗的,要找出指定的灯泡y
  2. ? x表示点亮第x个灯泡,同时返回abs(y左侧亮的灯泡数-y右侧亮的灯泡数)
  3. ! x 表示输出答案

由于绝对值的存在,二分check函数的判断很复杂。

  1. 若上一次询问返回的值等于这一次询问返回的值,则该灯泡就是答案,直接输出。
  2. 如果我们能使得左侧亮的灯泡数恒大于右侧亮的灯泡数,那么二分判断条件就明朗了
  3. 由于二分要进行logn次判断,那么我们先对前(1,logn)的灯泡进行询问。
  4. 然后对(logn,n)的区间进行二分,能保证在询问结束前左侧亮的灯泡数恒大于右侧亮的灯泡数。

同时看了dalao的题解,也可以将区间化为四等分判断解决。

The 1st Universal Cup. Stage 15: Hangzhou - 空気力学の詩 - 博客园

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include <iostream>
#include <utility>
using namespace std;
typedef long long LL;
const int N = 1e6 +10;
int arr[N];

typedef pair<int, int> PA;
typedef pair<PA, int> PA2;
int n,m;

int flag = 0;

int ans(int x)
{
cout << "? "<< x << endl;
cout.flush();
int tmp;
cin >> tmp;

return tmp;
}
void print(int x)
{
cout << "! " << x << endl;
cout.flush();
}

bool check(int x)
{
cout << "? "<< x << endl;
cout.flush();
int tmp;
cin >> tmp;
if(tmp ==flag+1)
{
flag = tmp;
return true;
}
else if (tmp == flag) {
print(x);
exit(0);
}
{
flag = tmp;
return false;
}

}

int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n;
int cnt = 0;
int nn = n;
while(nn)
{
cnt++;
nn >>= 1;
}
// cout << cnt << endl;
for(int i = 1; i <= cnt; i++)
{
int tmp = ans(i);
if(tmp == flag)
{
print(i);
return 0;
}
else {
flag = tmp;
}
}
//cout << flag << endl;
//cout << cnt << endl;
int left = cnt+1, right = n;
int ans = -1;
while (left <= right) {
int mid = left + (right - left) / 2; // 计算中间值
if (!check(mid)) { // 检查 mid 是否满足条件
ans = mid; // 更新答案
right = mid - 1; // 尝试更小的值
} else {
left = mid + 1; // 尝试更大的值
}
}
print(ans);
}