Problem
This is an interactive problem.
While procrastinating at work, Dilhan the elf stumbled upon two arrays a a a and b b b. Initially, both of them consist of a single integer 2 k 2^k 2k (i.e., a = b = [ 2 k ] a = b = [2^k] a=b=[2k]), where k k k is a non-negative integer.
Dilhan then applied the following two types of operations an arbitrary number of times (possibly zero), in any order:
- Flatten --- Choose either a a a or b b b, and select any element x x x that is maximal within that array ( x x x does not need to be maximal in the other array). Then, replace x x x with two copies of x 2 \frac{x}{2} 2x in the same position. This operation can only be applied if x x x is even.
- Concatenate --- Set both a a a and b b b to be a + b a + b a+b, where + + + denotes array concatenation.
After performing these operations, Dilhan discards b b b, hides a a a from you, and challenges you to a game.
Let n n n be the length of the hidden array a a a. You may make the following query:
- Choose an interval [ l , r ] [l, r] [l,r] ( 1 ≤ l ≤ r ≤ n 1 \leq l \leq r \leq n 1≤l≤r≤n), and Dilhan will tell you the sum a l + a l + 1 + ⋯ + a r a_l + a_{l+1} + \cdots + a_r al+al+1+⋯+ar.
Determine the value of the maximum element of a a a by making at most 300 queries.
Input
Each test contains multiple test cases. The first line contains the number of test cases t t t ( 1 ≤ t ≤ 100 1 \leq t \leq 100 1≤t≤100). The description of the test cases follows.
The first line of each test case contains a single integer n n n ( 1 ≤ n ≤ 10 5 1 \leq n \leq 10^5 1≤n≤105) --- the length of a a a.
It is guaranteed that 1 ≤ a i ≤ 2 30 1 \leq a_i \leq 2^{30} 1≤ai≤230, and the array a a a can be generated by the process described in the statements.
It is guaranteed that the sum of n n n over all test cases does not exceed 10 5 10^5 105.
Interaction
For each test case, you are first given an integer n n n --- the length of the hidden array a a a. You may then make up to 300 300 300 queries.
To make a query, print a line in the following format:
? l r( 1 ≤ l ≤ r ≤ n 1 \le l \le r \le n 1≤l≤r≤n) --- the indices chosen for the query.
After you print a query, the interactor will respond with a single integer --- the sum a l + a l + 1 + ⋯ + a r a_l + a_{l+1} + \dots + a_r al+al+1+⋯+ar.
To report that you have determined the value of the maximum element of a a a, print your answer in the following format:
! m( 1 ≤ m ≤ 2 30 1 \le m \le 2^{30} 1≤m≤230) --- the value of the maximum element.
Printing the answer does not count as one of the 300 300 300 queries.
Translation
这是一个交互式问题。
精灵 Dilhan 在工作摸鱼时偶然发现了两个数组 a a a 和 b b b。最初,这两个数组都只包含一个整数 2 k 2^k 2k(即 a = b = [ 2 k ] a = b = [2^k] a=b=[2k]),其中 k k k 是一个非负整数。
随后,Dilhan 以任意顺序进行了任意次数(可能为零次)的以下两种操作:
- 摊平 (Flatten) ------ 选择 a a a 或 b b b 中的一个,并选择该数组中最大的任意元素 x x x( x x x 不需要是另一个数组中的最大值)。然后,在相同位置将 x x x 替换为两个 x 2 \frac{x}{2} 2x。此操作仅在 x x x 为偶数时才能执行。
- 连接 (Concatenate) ------ 将 a a a 和 b b b 同时设为 a + b a + b a+b,其中 + + + 表示数组拼接。
在执行这些操作后,Dilhan 丢弃了 b b b,隐藏了数组 a a a,并向你发起挑战。
设 n n n 为隐藏数组 a a a 的长度。你可以进行以下查询:
- 选择一个区间 [ l , r ] [l, r] [l,r] ( 1 ≤ l ≤ r ≤ n 1 \leq l \leq r \leq n 1≤l≤r≤n),Dilhan 会告诉你该区间的元素之和 a l + a l + 1 + ⋯ + a r a_l + a_{l+1} + \cdots + a_r al+al+1+⋯+ar。
请在最多 300 次查询内确定数组 a a a 中最大元素的值。
输入格式
每个测试包含多个测试用例。第一行包含测试用例的数量 t t t ( 1 ≤ t ≤ 100 1 \leq t \leq 100 1≤t≤100)。接下来是各测试用例的描述。
每个测试用例的第一行包含一个整数 n n n ( 1 ≤ n ≤ 10 5 1 \leq n \leq 10^5 1≤n≤105) ------ 数组 a a a 的长度。
题目保证 1 ≤ a i ≤ 2 30 1 \leq a_i \leq 2^{30} 1≤ai≤230,且数组 a a a 可以通过上述过程生成。
题目保证所有测试用例中 n n n 的总和不超过 10 5 10^5 105。
交互
对于每个测试用例,首先会给你一个整数 n n n ------ 隐藏数组 a a a 的长度。随后你最多可以进行 300 300 300 次查询。
要进行查询,请按以下格式打印一行:
? l r( 1 ≤ l ≤ r ≤ n 1 \le l \le r \le n 1≤l≤r≤n) ------ 为查询选择的索引。
在你打印查询后,交互器将返回一个整数 ------ 即总和 a l + a l + 1 + ⋯ + a r a_l + a_{l+1} + \dots + a_r al+al+1+⋯+ar。
当你确定了数组 a a a 中最大元素的值后,按以下格式打印你的答案:
! m( 1 ≤ m ≤ 2 30 1 \le m \le 2^{30} 1≤m≤230) ------ 最大元素的值。
打印答案不计入 300 300 300 次查询之内。
Solutions
Approach 1
分治。
后半部分对于分治递归算法的设计和 Good Bye 2025 Editorial - Codeforces 题解差不多。下述大致思路。
首先,可以发现两个最基础的结论:
- 操作 1 不影响数组 a 的和。
- 操作 2 会让数组 a 的和翻倍。
在此基础上,因为对于题目中序列操作次数的不可知 (也就是基本不可能用在解题思路中),可以发现将 a 从初始的 2 k + 1 2^{k+1} 2k+1 变为 2 k , 2 k , 2 k , 2 k 2^k,2^k,2^k,2^k 2k,2k,2k,2k 有两种方案:可以先操作 1 再 2 ,或是先 2 再两次 1 。
再根据上述结论 2 ,这启发我们,可以将所有操作 2 移到最前面,并仅视为对初始 a 的翻倍 (即所有操作 2 的对 a 的影响可以用将 a 翻倍 + 额外的操作 1 等价实现,这很直观,也很显然是对的) 。
于是,假定所有操作 2 已经进行完,那么,全局只剩操作 1 可以使用。
问题变为从一个未知的 2 r 2^r 2r 开始,每次只能使用操作 1 ,其余不变。
于是通过查询 1 ∼ n 1 \sim n 1∼n 可以得到 2 r 2^r 2r 的值,进而,可以通过二分查询到每一次操作 1 的分界线在哪里。
接下来的核心点在于题目中的操作要求 ------ 分割的是"最大元素"。于是可以得到一个结论,当确定一个分界线后,哪边的长度更短,最大值就在哪边。
2026年1月2日01:17:27
好像也可以这么想:初始时,a 数组就是一个值为 2 k 2^k 2k 的树根,而一次操作 1 就是任选一个最浅的叶子节点,将两个值为一半的节点连上 (或者理解为分裂出两个值减半的子节点) ,而操作 2 就是从根复制一遍树移到旁边,然后新建一个根链接原来的两个根且值翻倍。这样,构成了一颗二叉树,且最后的序列 a 就是叶子节点从左向右构成的,而且,此时每一个节点的值就是子树节点的值的和。
这种等价下,上述的操作可能就会更容易理解了。
Code
cpp
#include<bits/stdc++.h>
using namespace std;
std::mt19937 rng(std::random_device{}());
typedef long double ld;
typedef long long ll;
typedef unsigned long long ull;
const int mod = 998244353;
const double ept = 1e-9;
ll add(ll x, const ll&y) { x += y; if(x >= mod) { x -= mod; } return x; }
ll sub(ll x, const ll&y) { x -= y; if(x < 0) { x += mod; } return x; }
ll mul(ll x, const ll&y) { x = x * y; if(x >= mod) { x %= mod; } return x; }
#ifndef ONLINE_JUDGE
#define DEBUG 1
#define fastio
#define coutd cout
#define db(i) cout << #i << ": " << i << endl;
#define dbl(fmt, ...) fprintf(stdout, fmt, ##__VA_ARGS__);
#define dbi(vec) { cout << #vec << ": "; for(auto &v: vec) { cout << v << ' '; } cout << endl; }
#define dbv(vec, a, b) { cout << #vec << ": "; for(int i=a; i!=b+sig(b-a); i+=sig(b-a)) { cout << vec[i] << ' '; } cout << endl; }
#else
#define DEBUG 0
#define fastio ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define coutd cerr
#define db(...)
#define dbl(fmt, ...)
#define dbi(vec)
#define dbv(vec, a, b)
#endif
ll c[100100];
ll query(int r) {
if(r == 0) return 0;
if(c[r] > 0) return c[r];
cout << "? " << 1 << ' ' << r << endl;
cin >> c[r];
return c[r];
}
void print(ll ans) {
cout << "! " << ans << endl;
}
int n;
void dfs(int dl, int dr, ll pre, ll sum) {
if(dl == dr) {
print(sum);
return;
}
else if(dl + 1 == dr) {
print(sum / 2);
return;
}
else if(dl + 2 == dr) {
print(sum / 2);
return;
}
int l = dl, r = dr, mid;
while(l < r) {
mid = l + (r-l) / 2;
if(query(mid) - pre >= sum/2) r = mid;
else l = mid + 1;
}
if(l - dl + 1 <= dr - l) dfs(dl, l, pre, sum/2);
else dfs(l+1, dr, pre + sum / 2, sum / 2);
}
void solve(int T) {
cin >> n;
for(int i=1; i<=n; i++) c[i] = 0;
ll sum = query(n);
dfs(1, n, 0, sum);
}
void init() {}
signed main() {
//freopen("1.in", "r", stdin);
//freopen("1.out", "w", stdout);
//cout.flags(ios::fixed); cout.precision(8);
fastio
init();
int T_=1;
std::cin >> T_;
for(int _T=1; _T<=T_; _T++) { solve(_T); }
return 0;
}