题目描述
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{30}30 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{30}30 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 3030 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⌋ 中不同数的个数。
- 你需要在 3030 次询问内找到 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.
题意简述
交互题。有一个排列 p_1,...,p_np1,...,pn, 你需要在 3030 次以内的询问后找出 11 的位置。每一次询问输出 ?\ l\ r\ k? l r k, 表示询问 \lfloor {p_l\over k} \rfloor,...,\lfloor {p_{r}\over k} \rfloor⌊kpl⌋,...,⌊kpr⌋ 中有多少个不同的数。
题目分析
首先发现 k=1k=1 的询问是一点用都没有的,不用考虑。而 k\geq2k≥2 时,\lfloor {1\over k}\rfloor⌊k1⌋ 总是 00, 为了让 11 与其它数区分开,我们考虑进行 k=2k=2 的询问,因为这样能让其它数除以 kk 下取整后不为 00。
当 nn 为奇数时,除了 11 以外的所有数除以 22 下取整后总是两两配对。因此当我们把 pp 分成两段分别询问时,两段中除 11 以外的未配对数的数量总是相等,所以 11 就应该在未配对数较多的一段中。采用二分的方法,最多询问 2\times\log(1024)=202×log(1024)=20 次,满足本题要求(甚至满足了 G3 的要求)。
而当 nn 为偶数时,有 11 与 nn 两个数没有配对,因此当询问的两段中未配对数相等时就很不好处理。但我们发现 nn 有个更特殊的性质,只有 \lfloor {n\over n} \rfloor⌊nn⌋ 为 11, 因此只需要在这时进行一次 k=nk=n 的询问就能找到 11 的位置了。同样用二分,最多询问 3\times\log(1024)=303×log(1024)=30 次,满足本题要求。
在 k=nk=n 的询问里,要注意不能询问长度为 11 的一段,否则起不到判断的作用,记得特判。
进一步的优化请看 G2 和 G3 的题解。
代码
#include <iostream>
#include <ctime>
#include <cstdio>
#include <cmath>
#include <vector>
#include <queue>
#include <cstring>
#include <algorithm>
#include <map>
#include <stdlib.h>
using namespace std;
int n;
inline int read()
{
int now=0,nev=1; char c=getchar();
while(c<'0' || c>'9') { if(c=='-') nev=-1; c=getchar();}
while(c>='0' && c<='9') { now=(now<<1)+(now<<3)+(c&15); c=getchar(); }
return now*nev;
}
int ask(int l,int r,int k)
{
printf("? %d %d %d\n",l,r,k);
fflush(stdout);
return read();
}
void putans(int x)
{
printf("! %d\n",x);
fflush(stdout);
}
bool check1(int x)
{
int a=ask(1,x,2);
int b=0;
if(x+1<=n)
{
b=ask(x+1,n,2);
}
int c=x-2*(x-a);
int d=(n-x)-2*((n-x)-b);
if(c>d)
{
return 1;
}
return 0;
}
void solve1()//n为奇数
{
int l=1,r=n;
while(l<r)
{
int mid=(l+r)>>1;
if(check1(mid))
{
r=mid;
}
else
{
l=mid+1;
}
}
putans(l);
}
bool check2(int x)
{
int a=ask(1,x,2);
int b=0;
if(x+1<=n)
{
b=ask(x+1,n,2);
}
int c=x-2*(x-a);
int d=(n-x)-2*((n-x)-b);
if(c>d)
{
return 1;
}
else if(c<d)
{
return 0;
}
else//两段未配对的数数量相等
{
int e=0;
if(x>1)//放在出现ask(1,1,n)的无效情况
{
e=ask(1,x,n);
}
else
{
e=3-ask(x+1,n,n);
}
if(e==2)
{
return 0;
}
else
{
return 1;
}
}
}
void solve2()//n为偶数
{
int l=1,r=n;
while(l<r)
{
int mid=(l+r)>>1;
if(check2(mid))
{
r=mid;
}
else
{
l=mid+1;
}
}
putans(l);
}
int main()
{
n=read();
if(n%2==1)
{
solve1();
}
else
{
solve2();
}
}