CF1856D More Wrong
题意
交互题,交互库中有一个长度为 $n$ 的排列 $a$,每次可以花费 $(r-l)^2$ 的代价向交互库询问区间 $[l,r]$ 内的逆序对个数。
在总花费不超过 $5\times n^2$ 的前提下找出排列 $a$ 中最大值的位置。
Solution
考虑分治,对于每个区间找出其最大值 $max$ 的位置。由于题目保证为排列,对于左右区间的最大值 $x$ 和 $y$,可以发现有如下性质:如果区间 $[x,y]$ 内的逆序对个数和区间 $[x,y-1]$ 内的逆序对个数相同,则表示 $y$ 对于区间 $[x,y]$ 内没有贡献,即区间 $[x,y-1]$ 内的数均小于 $y$。故 $y$ 为区间最大值,否则 $x$ 为区间最大值。
总代价表达式为$$ cost(n)=cost(\frac{n}{2})+(n-1)^2+(n-2)^2 $$
$$ \le cost(\frac{n}{2})+2\times n^2 $$
由主定理:$$ cost(n)\leq 4\times n^2 $$ 时间复杂度为 $\mathcal{O}(n \log n)$,代价小于等于 $4\times n^2$,可以通过本题。
code
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int res=0,flag=1;
char ch=getchar();
while(!isalnum(ch)) (ch=='-')?flag=-1:1,ch=getchar();
while(isalnum(ch)) res=res*10+ch-'0',ch=getchar();
return res*flag;
}
int query(int left,int right)
{
if(left==right)
return 0;
printf("? %d %d\n",left,right);
cout.flush();
return read();
}
int solve(int left,int right)
{
if(left==right)
return left;
int mid=(left+right)>>1;
int a=solve(left,mid);
int b=solve(mid+1,right);
if(query(a,b-1)==query(a,b))
return b;
return a;
}
int main(int argc,const char *argv[])
{
int T=read();
while(T--)
{
int n=read();
printf("! %d\n",solve(1,n));
cout.flush();
}
return 0;
}

浙公网安备 33010602011771号