1. Description
- start:: 2023-08-07 Finish
2. Solution
交互题 , 首先观察交互操作与待求值之间的联系.
交互操作可以获得逆序对的个数 , 那么可以得到如下关系 :
一个数是最大的充要条件是 , 它和前面的逆序对为 0 , 和后面的逆序对为长度
所以可以得到一个最基础的算法 , 对每一个数四次算出前后逆序对数
但是代价远远超出限制 , 想办法优化 , 而求最大值是一个 RMQ 模型
所以可以尝试分治
假设 i = id(max(a[l,mid]))
, j=id(max(a[mid+1,r]))
那么只需要知道 i
和 j
之间的大小关系 , 就知道了 id(max(a[l,r]))
, 分治过程就可以继续
由上述最大值的充要条件可以得到 , 只要 a[i]
和 a[i+1,j]
这一段的逆序对个数为 j-i
, 那么最大值就是 i
, 否则就是 j
考虑复杂度 , 分治过程有 log n \log n logn 层 , 第 i i i 层有不超过 2 i − 1 2^{i-1} 2i−1 个长度不超过 n / 2 i − 1 n / 2^{i-1} n/2i−1 的块
每一块进行一次向上合并的代价为 ( n / 2 i − 2 ) 2 (n/2^{i-2})^2 (n/2i−2)2 , 那么一层的代价就是 ( n / 2 i − 2 ) 2 × 2 i − 1 = 2 n 2 / 2 i − 2 (n/2^{i-2})^2 \times 2^{i-1} = 2n^2/2^{i-2} (n/2i−2)2×2i−1=2n2/2i−2 , 合并过程从第 log n \log n logn 层进行到第 2 层 , 所以总复杂度为
2 ∑ i = 2 log n n 2 2 i − 2 ≤ 2 × n 2 × 2 = 4 n 2 2\sum_{i=2}^{\log n} \frac{n^2}{2^{i-2}} \leq 2 \times n^2 \times 2 = 4n^2 2i=2∑logn2i−2n2≤2×n2×2=4n2
满足条件.
3. Code
#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;
typedef const int& cint;
typedef const ll& cll;
typedef pair<int, int> pii;
typedef pair<int, ll> pil;
#define ls (loc<<1)
#define rs ((loc<<1)|1)
const int mod1 = 1e9+7;
const int mod2 = 998244353;
const int inf_int = 0x7fffffff;
const int hf_int = 0x3f3f3f3f;
const ll inf_ll = 0x7fffffffffffffff;
const double ept = 1e-9;
int n;
int query(int l, int r) {
if(l == r) { return 0; }
int tmp;
cout << "? " << l << ' ' << r << endl;
cin >> tmp;
return tmp;
}
int dfs(int l, int r) {
if(l == r) { return l; }
if(l + 1 == r) {
int c = query(l, r);
return c == 0 ? r : l;
}
int mid = (l+r) >> 1;
int i = dfs(l, mid), j = dfs(mid+1, r);
if(i+1 == j) {
int a = query(i, j);
return a == 0 ? j : i;
}
else {
int a = query(i, j), b = query(i+1, j);
int st = a - b;
return st == j-i ? i : j;
}
}
void solve(cint T) {
cin >> n;
int ans = dfs(1, n);
cout << "! " << ans << endl;
}
int main() {
//freopen("1.in", "r", stdin);
//cout.flags(ios::fixed); cout.precision(8);
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int T_=1;
std::cin >> T_;
for(int _T=1; _T<=T_; _T++)
solve(_T);
return 0;
}