CF1712D 题解

CF1712D Empty Graph#

思路:#

赛时想到了一个 O(nlognlogA) (A 表示值域)的解法。

先考虑 xy (x<y) 的最短距离 disx,y 怎么更新。

( 我们假定 mnl,r 表示 min{al,al+1ar} )

显然 disx,y 由三部分取最小值组成:

  • x 直接到 y,这部分的距离是 mnx,y

  • x 先到 z 再到 y,且满足 z<x,这部分的距离是 mnz,x+mnz,y

  • x 先到 z 再到 y,且满足 z>y,这部分的距离是 mnx,z+mny,z

显然,第二部分当 z=1 时有最小值 mn1,x+mn1,y,第三部分当 z=n 时有最小值 mnx,n+mny,n

然后我发现答案满足单调性,于是二分答案 mid,并且修改 axy 中值小于 mid 的,这样对于第二部分和第三部分,由于 mnx,ymid,实际上我们只用使 2mn1,x1mid2mny+1,nmid

也就是我们需要修改 1ix1y+1inaimid2 中的 ai,然后判断总修改次数是否大于 k 次即可。

我们可以维护一棵主席树来计算需要修改的数,这样做的时间复杂度是 O(n2lognlogA) 的,显然需要一些优化。

然后我大胆猜测对于每一个数 y 能使得修改次数最小的 x 必然是 y1,赛时交了一发,然后就过了。

赛后证明一下:

如果选 x,y 的话,必然需要使得 a1x1,y+1nmid2axymid

x=y1 的话那么就可以让 axymidai 尽量少,这样限制条件就更少 (只用 mid2),也就使得修改的次数更少,也就说明 x=y1 时最优,证毕。

这样的时间复杂度是 O(nlognlogA) 的,而数据范围是 1n105 ,故能够通过此题。

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;
	}
}

当然还有时间复杂度更加优秀的做法,具体可以去看官方题解。

作者:Into_qwq

出处:https://www.cnblogs.com/into-qwq/p/16586192.html

版权:本作品采用「qwq」许可协议进行许可。

posted @   Into_qwq  阅读(48)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示