Doremy‘s Perfect DS Class (Medium Version)

 

题目描述

The only difference between this problem and the other two versions is the maximum number of queries. In this version, you are allowed to ask at most \mathbf{25}25 queries. You can make hacks only if all versions of the problem are solved.

This is an interactive problem.

"Everybody! Doremy's Perfect Data Structure Class is about to start! Come and do your best if you want to have as much IQ as me!" In today's Data Structure class, Doremy is teaching everyone a powerful data structure — Doremy tree! Now she gives you a quiz to prove that you are paying attention in class.

Given an array aa of length mm , Doremy tree supports the query Q(l,r,k)Q(l,r,k) , where 1 \leq l \leq r \leq m1≤l≤r≤m and 1 \leq k \leq m1≤k≤m , which returns the number of distinct integers in the array \left[\lfloor\frac{a_l}{k} \rfloor, \lfloor\frac{a_{l+1}}{k} \rfloor, \ldots, \lfloor\frac{a_r}{k} \rfloor\right][⌊kal​​⌋,⌊kal+1​​⌋,…,⌊kar​​⌋] .

Doremy has a secret permutation pp of integers from 11 to nn . You can make queries, in one query, you give 33 integers l,r,kl,r,k ( 1 \leq l \leq r \leq n1≤l≤r≤n , 1 \leq k \leq n1≤k≤n ) and receive the value of Q(l,r,k)Q(l,r,k) for the array pp . Can you find the index yy ( 1 \leq y \leq n1≤y≤n ) such that p_y=1py​=1 in at most \mathbf{25}25 queries?

Note that the permutation pp is fixed before any queries are made.

输入格式

输出格式

You begin the interaction by reading an integer nn ( 3 \le n \le 10243≤n≤1024 ) in the first line — the length of the permutation.

To make a query, you should output

  • "? l\ r\ kl r k " ( 1 \leq l \leq r \leq n1≤l≤r≤n , 1 \leq k \leq n1≤k≤n )

in a separate line. After each query, you should read an integer xx — the value of Q(l,r,k)Q(l,r,k) for pp . In this version of the problem, you can make at most 2525 such queries.To give the answer, you should output

  • "! yy " ( 1 \leq y \leq n1≤y≤n )

in a separate line, where p_y=1py​=1 .After printing a query or the answer, do not forget to output the end of line and flush the output. Otherwise, you will get Idleness limit exceeded. To do this, use:

  • fflush(stdout) or cout.flush() in C++;
  • System.out.flush() in Java;
  • flush(output) in Pascal;
  • stdout.flush() in Python;
  • see documentation for other languages.

Hacks Format

The first line of the hack contains an integer nn ( 3 \le n \le 10243≤n≤1024 ) — the length of the permutation.

The second line of the hack contains nn distinct integers p_1,p_2,\ldots,p_np1​,p2​,…,pn​ ( 1 \le p_i\le n1≤pi​≤n ) — the permutation.

题意翻译

  • 这是一道交互题。
  • 交互库有一个 [1,n][1,n] 的排列 pp。
  • 你可以询问 l,r,kl,r,k,交互库会返回 \left\lfloor\dfrac{p_l}k\right\rfloor,\left\lfloor\dfrac{p_{l+1}}k\right\rfloor,\cdots,\left\lfloor\dfrac{p_r}k\right\rfloor⌊kpl​​⌋,⌊kpl+1​​⌋,⋯,⌊kpr​​⌋ 中不同数的个数。
  • 你需要在 2525 次询问内找到 pp 中 11 的位置。
  • n\in[3,1024]n∈[3,1024]。

输入输出样例

输入 #1复制

5

2

2

1

3

输出 #1复制

? 1 3 4

? 3 5 3

? 3 4 5

? 3 5 2

! 4

说明/提示

The permutation in the example is [3,5,2,1,4][3,5,2,1,4] .

The input and output for example illustrate possible interaction on that test (empty lines are inserted only for clarity).

In this interaction process:

  • For the first query, \lfloor\frac{3}{4}\rfloor=0,\lfloor\frac{5}{4}\rfloor=1,\lfloor\frac{2}{4}\rfloor=0⌊43​⌋=0,⌊45​⌋=1,⌊42​⌋=0 , so the answer is 22 .
  • For the second query, \lfloor\frac{2}{3}\rfloor=0,\lfloor\frac{1}{3}\rfloor=0,\lfloor\frac{4}{3}\rfloor=1⌊32​⌋=0,⌊31​⌋=0,⌊34​⌋=1 , so the answer is still 22 .
  • For the third query, \lfloor\frac{2}{5}\rfloor=0,\lfloor\frac{1}{5}\rfloor=0⌊52​⌋=0,⌊51​⌋=0 , so the answer is 11 .
  • For the fourth query, \lfloor\frac{2}{2}\rfloor=1,\lfloor\frac{1}{2}\rfloor=0,\lfloor\frac{4}{2}\rfloor=2⌊22​⌋=1,⌊21​⌋=0,⌊24​⌋=2 , so the answer is 33 .

The correct answer is got after 44 queries, so this process will be judged correct.

 

G1

考虑 11 和其他的数有什么不同点。我们令询问的 k=2k=2,那么只有 11 的值是 00,其余都不是。这看起来并没有什么用,因为我们只能知道不同的数的个数。

但是真的没有用吗?可以发现,若 k=2k=2,则所有数下取整后是两两配对的,\lfloor\frac{2}{2}\rfloor=\lfloor\frac{3}{2}\rfloor,\lfloor\frac{4}{2}\rfloor=\lfloor\frac{5}{2}\rfloor,\dots⌊22​⌋=⌊23​⌋,⌊24​⌋=⌊25​⌋,…。当 nn 为奇数时,只有 11 是单出来的;nn 为偶数时,11 和 nn 两个数都是单出来的。

先考虑奇数的情况怎么做。

对于一个区间 [l,r][l,r],若 \text{query}(l,r,2)=xquery(l,r,2)=x,可以得到 [l,r][l,r] 中有 2x-(r-l+1)2x−(r−l+1) 个数字没有被配对。所以假设我们找了一个分界点 midmid,并求出 [1,mid][1,mid] 中有 LL 个没配对,[mid+1,n][mid+1,n] 中有 RR 个没配对。那么如果同一组的数分到了一边一个,它们可以互相消掉,只有 11 是无论如何都无法被配对的。

这就是说,若 L<RL<R,11 就在 [mid+1,n][mid+1,n] 中;否则 11 在 [1,mid][1,mid] 中。那么我们可以二分这个 midmid 的位置,求出答案,询问次数 2\log n\le 202logn≤20。

再考虑 nn 是偶数的情况。

现在,我们同样询问得到了 LL 和 RR 的值。分类讨论 11 和 nn 的位置情况:

  • 如果都在左侧,应该是 L=R+2L=R+2;
  • 如果都在右侧,应该是 R=L+2R=L+2;
  • 如果一左一右,L=RL=R。

发现在一左一右的情况下,我们没法判断哪一边是 11。

但仔细思考一下,发现 nn 的位置是好找的:令 k=nk=n,这样只有 nn 的答案是 11,其他都是 00。因此可以在一开始先二分找出 nn 的位置,就能知道 L=RL=R 时 11 在哪边了。

找 nn 的位置只需要询问一边,所以总询问次数是 3\log n\le 303logn≤30。

G2

发现找 11 的位置的过程是不好优化的,现在的询问次数瓶颈在找 nn 的位置。

实际上,我们只关心 nn 在 midmid 的哪一侧,而不关心它的具体位置。可以这样优化:

  • 当第一次出现 L=RL=R 的情况时,我们通过一次 \text{query}(1,mid,n)query(1,mid,n) 判断 nn 在 midmid 的哪一侧。
  • 当再次出现这个情况时,发现有一条性质:如果之前判断过 nn 在 midmid 的右侧,我们的二分区间只会往左不会往右,也就是说以后 nn 永远在 midmid 的右侧,反之同理。

因此,在第一次判断时记录 nn 在 midmid 的哪一侧,以后不需要再次判断。总询问次数为 2\log n+1\le 212logn+1≤21。

const int N=2005;
int n,L[N],R[N];
il int ask(int l,int r,int k)
{
    cout<<"? "<<l<<" "<<r<<" "<<k<<endl;
    int x=read();
    if(k==2) {if(l==1) L[r]=2*x-(r-l+1); if(r==n) R[l]=2*x-(r-l+1);}
    return x;
}
bool flag,pos;
int main()
{
    n=read();
    int l=1,r=n;
    while(l<r)
    {
        int mid=(l+r)>>1;
        ask(1,mid,2),ask(mid+1,n,2);
        if(L[mid]>R[mid+1]) r=mid;
        else if(L[mid]<R[mid+1]) l=mid+1;
        else 
        {
            if(!flag) 
            {
                if(mid>1) pos=(ask(1,mid,n)>1);
                else pos=(ask(mid+1,n,n)==1);
                flag=1;
            }
            if(pos) l=mid+1; else r=mid;
        }
    }
    cout<<"! "<<l<<endl;
    return 0;
}
  • 26
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值