cf1856d - More Wrong

Problem - 1856D - Codeforces

better

1. Description

  • start:: 2023-08-07 Finish

2. Solution

交互题 , 首先观察交互操作与待求值之间的联系.

交互操作可以获得逆序对的个数 , 那么可以得到如下关系 :

一个数是最大的充要条件是 , 它和前面的逆序对为 0 , 和后面的逆序对为长度

所以可以得到一个最基础的算法 , 对每一个数四次算出前后逆序对数

但是代价远远超出限制 , 想办法优化 , 而求最大值是一个 RMQ 模型
所以可以尝试分治

假设 i = id(max(a[l,mid])) , j=id(max(a[mid+1,r]))

那么只需要知道 ij 之间的大小关系 , 就知道了 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} 2i1 个长度不超过 n / 2 i − 1 n / 2^{i-1} n/2i1 的块

每一块进行一次向上合并的代价为 ( n / 2 i − 2 ) 2 (n/2^{i-2})^2 (n/2i2)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/2i2)2×2i1=2n2/2i2 , 合并过程从第 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=2logn2i2n22×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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值