题解:CF1973D Cat, Fox and Maximum Array Split

· · 题解

题意

给出长度为 n 的数组和整数 k,定义 f(l, r) = (r - l + 1)\times\max_{x=l}^ra_x,询问是否存在一个最大值 m,使得把 a 数组分成 k 段后,使得每段 f(l,r)=m 都成立。若无解 m=-1。输出 m

你可以询问交互库 2n 次,每次给出 l,x 两个参数,交互库会回答一个满足 f(l,r)=x 最小的 r如果不存在 r,则交互库会回答 n+1

注意,你并不知道 a 数组中的元素。

交互库询问格式:? l x

答案输出格式:! m

注意输出空行和刷新。

对于每次你输出的答案,如果正确,交互库会给出 1,错误则给出 -1。请使用一个变量存储这个输入。

## 思路 神秘交互题。 首先,题目只给了我们 $2n$ 次询问交互库的次数,这让我们只能往线性方面思考。 观察答案有什么特点,明显的,答案总有一个区间覆盖了 $m=\max_{x=1}^na_x$。 我们不妨往这个方向思考一番。根据 $m$ 总会被区间覆盖,而且长度不固定,不难得出 $ans$ 如果存在一定是 $m$ 的倍数。 现在我们缩小了答案的区间。 我们想想怎么得到 $m$。不难发现,$f(1,n)=m\times n$,是固定的。我们可以通过从小到大询问 $m\times n$ 来得到 $m$。最劣情况下,我们使用了 $n$ 次询问。 我们现在知道了答案的下界,那么能不能推个上界出来呢? 根据 $f$ 这个式子的优良性质,我们可以得到一个显然的结论:$f(l,r)\ge f(l,k)+f(k+1,r)$。 假设 $ans=t\times m$。 我们可以归纳得到:$ans\times k\le f(1,n)$。 然后变一下这个式子:$t\times m\times k\le n\times m$。 所以 $t\le \frac{n}{k}$。 现在做法已经很明显了。我们枚举每个 $m$ 的倍数,总共会枚举 $\frac{n}{k}$ 次,然后每次验证答案最多会询问 $k$ 次,最多询问 $n+\frac{n}{k}\times k=2n$ 次。在答案中取最大值即可,可以通过此题。 最后留给读者一个思考:其实如果存在答案的话,答案是唯一的。读者可以自己证明一下。 code ```cpp #include<bits/stdc++.h> #define ll long long #define N 10005 using namespace std; int n,k,m,res; int g; int main() { scanf("%d",&g); while(g--) { scanf("%d%d",&n,&k); for(int i=n;i>=1;i--) { int x; printf("? %d %d\n",1,n*i); fflush(stdout); scanf("%d",&x); if(x<=n) { m=i; break; } } res=0; for(int i=1;i<=n/k;i++) { bool ok=1; int lst=1; for(int j=1;j<=k;j++) { if(lst>n) { ok=0; break; } int x; printf("? %d %d\n",lst,i*m); fflush(stdout); scanf("%d",&x); lst=x+1; } if(lst!=n+1) ok=0; if(ok) { res=1; printf("! %d\n",i*m); fflush(stdout); break; } } if(!res) { printf("! -1\n"); fflush(stdout); } scanf("%d",&res); } return 0; } ```