首页 > 其他分享 >Codeforces 1832F - Zombies(wqs 二分)

Codeforces 1832F - Zombies(wqs 二分)

时间:2023-05-19 10:57:02浏览次数:49  
标签:int 要么 wqs Codeforces mid 交集 MAXN Zombies 区间

等价于最大化 \(n\) 对区间的交集之和。而对于每个 \([l_i,r_i)\) 我们肯定会选择与其交集最大的 \([p,p+m)\) 与之匹配,所以我们只用对 \(k\) 个区间进行决策即可。

首先先发现一个东西:存在一种最优解,使得对于每个选择的区间 \([p,p+m)\),要么有 \(p=l_i\),要么有 \(p+m=r_i\),也就是每个选择的区间要么顶着某个输入的区间的左端点,要么顶着某个输入的区间的右端点。感性理解一下是因为对于一个不顶着左右端点的区间,要么向左移动交集呈增大的趋势,要么向右移动呈增大的趋势。

猜测答案具有凸性,因此考虑 wqs 二分。注意到对于一个区间 \([l_i,r_i)\) 而言,与其交集最大的一定所有是 \([p,p+m)\) 中,\(2p+m\) 与 \(l_i+r_i\) 最接近的那个。因此考虑将所有可能选择的 \(p\) 从大到小排序,二分到 \(mid\) 的时候设 \(dp_i\) 表示考虑了前 \(i\) 个关键点,第 \(i\) 个关键点表示的区间被选择时能够得到的最大交集 \(-mid\times\text{选择的区间个数}\),转移就枚举上一个关键点 \(j\),然后考虑那些 \(l_t+r_t\in (2p_j+m,2p_i+m]\) 的区间,显然是前一半选择 \(j\),后一半选择 \(i\),预处理这个贡献即可。

时间复杂度 \(n^2(\log n+\log V)\)。

const int MAXN=2000;
int n,k,x,m,l[MAXN+5],r[MAXN+5],key[MAXN*2+5],uni[MAXN*2+5],cnt,num,ord[MAXN+5];
ll sum[MAXN*2+5][MAXN+5],cst[MAXN*2+5][MAXN*2+5];
int find_pos(int x){
	int L=1,R=n,p=0;
	while(L<=R){
		int mid=L+R>>1;
		if(l[ord[mid]]+r[ord[mid]]<=x)p=mid,L=mid+1;
		else R=mid-1;
	}return p;
}
ll calc(int id,int l,int r){
	int pl=find_pos(l-1),pr=find_pos(r);
	return sum[id][pr]-sum[id][pl];
}
pair<ll,int>dp[MAXN+5];
pair<ll,int>check(int mid){
	for(int i=1;i<=num;i++)dp[i]=mp(calc(i,0,uni[i]*2+m)-mid,-1);
	for(int i=1;i<=num;i++)for(int j=1;j<i;j++)chkmax(dp[i],mp(dp[j].fi+cst[j][i]-mid,dp[j].se-1));
	pair<ll,int>res=mp(0,0);
	for(int i=1;i<=num;i++)chkmax(res,mp(dp[i].fi+calc(i,uni[i]*2+m+1,2e9),dp[i].se));
	return mp(res.fi,-res.se);
}
int main(){
	scanf("%d%d%d%d",&n,&k,&x,&m);
	for(int i=1;i<=n;i++)scanf("%d%d",&l[i],&r[i]),ord[i]=i;
	sort(ord+1,ord+n+1,[&](int x,int y){return l[x]+r[x]<l[y]+r[y];});
	for(int i=1;i<=n;i++)key[++cnt]=min(x-m,l[i]),key[++cnt]=max(0,r[i]-m);
	sort(key+1,key+cnt+1);key[0]=-1;
	for(int i=1;i<=cnt;i++)if(key[i]!=key[i-1])uni[++num]=key[i];
	for(int i=1;i<=num;i++)for(int j=1;j<=n;j++){
		int id=ord[j],L=max(l[id],uni[i]),R=min(r[id],uni[i]+m);
		sum[i][j]=sum[i][j-1]+max(R-L,0);
	}
	for(int i=1;i<=num;i++)for(int j=i+1;j<=num;j++){
		ll L=uni[i]*2+m,R=uni[j]*2+m,mid=L+R>>1;
		cst[i][j]=calc(i,L+1,mid)+calc(j,mid+1,R);
//		printf("cst[%d][%d]=%lld\n",i,j,cst[i][j]);
	}
//	for(int i=1;i<=num;i++)printf("%d%c",uni[i]," \n"[i==num]);
	int L=0,R=1e9,p=0;
	while(L<=R){
		int mid=L+R>>1;
		if(check(mid).se<=k)p=mid,R=mid-1;
		else L=mid+1;
	}pair<ll,int>pp=check(p);ll tot=pp.fi+1ll*p*k,sum=1ll*x*n;
	for(int i=1;i<=n;i++)sum-=r[i]-l[i],sum-=m;sum+=tot;
	printf("%lld\n",sum);
	return 0;
}

标签:int,要么,wqs,Codeforces,mid,交集,MAXN,Zombies,区间
From: https://www.cnblogs.com/tzcwk/p/Codeforces-1832F.html

相关文章

  • Codeforces Round 873 (Div. 2)
    Preface补题,这场本来周日晚上打算现场打的但一来第二天要上课怕熬太晚影响早上的微积分和电分,二来那天晚上开了DP专题然后就在手速抢一血过程中被两道DFS搞红温了,本来打CF的计划也咕咕咕了今天差不多想起来好久没做CF了赶紧补一场看了下自己补题的时候2h也才堪堪做完D1,虽然后......
  • Codeforces Round 703 (Div. 2) A-D
    CodeforcesRound703(Div.2) A.ShiftingStacksinta[N];voidsolve(){intn=read(),ans=1;for(inti=1;i<=n;i++)a[i]=read();intrest=0,last=-1;for(inti=1;i<=n;i++){a[i]+=rest;rest=a[i]-last-1;last++......
  • Codeforces Round 868 (Div. 2) A-D
    CodeforcesRound868(Div.2) A.A-characteristicintfac[N];map<int,int>mp;voidinit(){fac[1]=0;mp[0]=1;for(inti=2;i<N;i++){fac[i]=fac[i-1]+(i-1);mp[fac[i]]=i;}}voidsolve(){intn=read(),k=rea......
  • CF1832F Zombies
    简要题意给定\(n\)个左闭右开的区间\(A_i=[L_i,R_i)\),其中\(0\leL_i<R_i\lex\),你可以自由选择\(k\)个长度为\(m\)左闭右开的区间\(B_j=[l_j,r_j)\)使得\(0\lel_j<r_j\lex\)。区间长度定义为内部整点个数。接下来给每个\(A\)中的区间\(A_i\)分配唯一......
  • Codeforces Round 873 (Div. 2)
    CodeforcesRound873(Div.2)链接CodeforcesRound873(Div.2)A题打印2-n并且计算总和,然后找到严格大于sum的n的倍数记为x,然后用这个x减去sum得到a.然后先打印a然后再打印2-n#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>#include......
  • Codeforces Round 767 (Div. 1) E. Groceries in Meteor Town (Kruskal重构树 + 线段
    传送门  出现最大路径权值就应该联想到克鲁斯卡尔重构树,我们对于克鲁斯卡尔重构树求一遍dfs序,维护所有白色点的最大最小dfn(包括出发点),求出最大最小dfn的最近公共祖先既是答案。注意需要特判一下除了本身以外没有白色点情况。#include<bits/stdc++.h>intn,m;constintN......
  • Codeforces Round 873 A~E
    CodeforcesRound873(Div.1)A.CountingOrders对于每个\(a_i\),可以计算出\(c_i\)表示有多少个\(b_j\lta_i\)。那么第\(i\)个人就有\(c_i\)种可能的位置。注意到如果将\(a\)升序排序,则能放的位置集合从前往后是包含的关系。所以将\(a\)排序(等价于将\(c\)排序......
  • Educational Codeforces Round 148 (Rated for Div. 2) A-D2
    EducationalCodeforcesRound148(RatedforDiv.2) A.NewPalindromemap<int,int>mp;voidsolve(){strings;mp.clear();cin>>s;for(inti=0;i<s.size()/2;i++){mp[s[i]]++;}puts(mp.size()>=2?"YES......
  • CodeForces 1827 D Two Centroids
    洛谷传送门CF传送门考虑固定一个重心,设\(k\)为重心最大子树大小,答案为\(n-2k\)。构造方法是往最大的子树塞叶子。树的重心有一个很好的性质,就是加一个叶子,重心最多移动一条边的距离。简单证一下,设重心为\(x\),往儿子\(u\)的子树中加叶子。如果\(sz_u>\left\lfloor......
  • CodeForces 1827 B Range Sorting
    洛谷传送门CF传送门考虑拆贡献\(i-1\simi\),发现当\([1,i-1]\)的最大值大于\([i,n]\)的最小值时\(i-1\simi\)产生\(1\)的贡献。考虑枚举左端点\(j\),设\(x=\max\limits_{k=j}^{i-1}a_k\)。设\(i\)及\(i\)以后第一个\(<x\)的数位置是\(p\),那么......