1 条题解
-
0
自动搬运
来自洛谷,原作者为

konyakest
**搬运于
2025-08-24 23:15:37,当前版本为作者最后更新于2025-05-10 15:43:13,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
挑战最短代码。
显然,原问题等价于求出每个区间的次大值下标。于是我们可以打表观察区间次大值的结构。
例如,当 时,我们可以打出以下表:(第 行第 列表示区间 的次大值下标,若不存在则为 )。
0 1 1 4 2 2 2 2 2 0 0 3 4 2 2 2 2 2 0 0 0 3 4 6 6 8 8 0 0 0 0 4 6 6 8 8 0 0 0 0 0 6 6 8 8 0 0 0 0 0 0 7 6 6 0 0 0 0 0 0 0 7 9 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0观察发现,每个元素最多占据两个矩形区域。下文中用 的形式表示一个矩形区域。
证明:
考虑一个元素何时成为区间次大值。
设 表示 前面最后一个比 大的位置, 表示 前面倒数第二个比 大的位置; 表示 后面最前一个比 大的位置, 表示 后面第二个比 大的位置。
则 成为次大值的区域为:
$$[prepre_i+1,pre_i]\times [i,nxt_i-1]\cup [pre_i+1,i]\times [nxt_i,nxtnxt_i-1] $$于是我们定位到每个矩形即可。
考虑递归进行这个过程。如果我们知道 内最大值下标为 ,次大值下标为 ,不妨令 。
此时我们可以提取出矩形 ,往 递归即可。
递归时进行记忆化,则每个矩形恰好被递归一次,总递归次数为 。
除第一次外区间的最大值下标可以在递归时传下去。第一次使用 次询问查询即可。总次数为 。
code:
#include<bits/stdc++.h> #define rep(i,j,k,...) for(int i=j;i<=k;i++) using namespace std; const int maxn=2070; int a[maxn],n; int ans[maxn][maxn]; int ask(int l,int r){ cout<<"? "<<l<<" "<<r<<endl; int x; cin>>x; return x; } bool vis[maxn][maxn]; void solve(int l,int r,int mx){ if(l==r) return; if(vis[l][r]) return; vis[l][r]=1; int se=ask(l,r),x,y; tie(x,y)=minmax(mx,se); rep(i,l,x) rep(j,y,r) ans[i][j]=se; solve(l,y-1,x),solve(x+1,r,y); } signed main(){ cin>>n; int x=ask(1,n),l=x,r=x; while(r!=n&&ask(l,r+1)!=x) r++; while(l!=1&&ask(l-1,r)!=x) l--; int pos=(l==1? r+1: l-1); solve(1,n,pos); cout<<"!"<<endl; int q; cin>>q; while(q--){ int l,r; cin>>l>>r; cout<<ans[l][r]<<endl; } }
- 1
信息
- ID
- 12219
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者