CF1712D 题解
#
思路:#
赛时想到了一个 ( 表示值域)的解法。
先考虑 的最短距离 怎么更新。
( 我们假定 表示 )
显然 由三部分取最小值组成:
-
直接到 ,这部分的距离是
-
先到 再到 ,且满足 ,这部分的距离是
-
先到 再到 ,且满足 ,这部分的距离是
显然,第二部分当 时有最小值 ,第三部分当 时有最小值 。
然后我发现答案满足单调性,于是二分答案 ,并且修改 中值小于 的,这样对于第二部分和第三部分,由于 ,实际上我们只用使 且 。
也就是我们需要修改 和 且 中的 ,然后判断总修改次数是否大于 次即可。
我们可以维护一棵主席树来计算需要修改的数,这样做的时间复杂度是 的,显然需要一些优化。
然后我大胆猜测对于每一个数 能使得修改次数最小的 必然是 ,赛时交了一发,然后就过了。
赛后证明一下:
如果选 的话,必然需要使得 且 。
的话那么就可以让 的 尽量少,这样限制条件就更少 (只用 ),也就使得修改的次数更少,也就说明 时最优,证毕。
这样的时间复杂度是 的,而数据范围是 ,故能够通过此题。
code:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
const int inf=1e9;
int n,k;
int a[N],rt[N];
namespace CT{
struct node{
int v,l,r;
}t[N*31];
int cnt;
inline void insert(int &p,int pre,int l,int r,int x,int k){
p=++cnt;
t[p]=t[pre];
++t[p].v;
if(l==r) return;
int mid=l+r>>1;
if(x<=mid) insert(t[p].l,t[pre].l,l,mid,x,k);
else insert(t[p].r,t[pre].r,mid+1,r,x,k);
}
inline int query(int q,int p,int l,int r,int L,int R){
if(L<=l&&r<=R) return t[p].v-t[q].v;
int mid=l+r>>1,res=0;
if(L<=mid) res+=query(t[q].l,t[p].l,l,mid,L,R);
if(mid<R) res+=query(t[q].r,t[p].r,mid+1,r,L,R);
return res;
}
}
inline bool check(int x,int i){
int now=0;
if(a[i]<x) ++now;
if(a[i-1]<x) ++now;
int num=x/2+(x%2);
if(now>k) return 0;
if(num==1) return 1;
now+=CT::query(rt[0],rt[i-2],1,inf,1,num-1);
now+=CT::query(rt[i],rt[n],1,inf,1,num-1);
//cout<<x<<" "<<i<<" "<<num<<" "<<now<<endl;
return now<=k;
}
signed main(){
int T;
cin>>T;
while(T--){
cin>>n>>k;
int ans=0;
rt[0]=0;
for(int i=1;i<=n;++i){
cin>>a[i];
CT::insert(rt[i],rt[i-1],1,inf,a[i],1);
}
for(int i=2;i<=n;++i){
int l=1,r=1e9+1;
while(l<r-1){
int mid=l+r>>1;
if(check(mid,i)) l=mid;
else r=mid;
}
ans=max(ans,l);
}
cout<<ans<<endl;
}
}
当然还有时间复杂度更加优秀的做法,具体可以去看官方题解。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现