首页 > 其他分享 >题解 P9474 [yLOI2022] 长安幻世绘

题解 P9474 [yLOI2022] 长安幻世绘

时间:2023-07-23 19:57:22浏览次数:45  
标签:tmp get int 题解 yLOI2022 幻世绘 st mkp it2

看到极差,不难想到双指针。

显然,如果 \([l,r]\) 的位置都被覆盖,那么其中最多可以选 \(\lceil\frac{r-l+1}{2}\rceil\) 个数。

我们先将所有数离散化,排序,双指针卡取值范围。

set 里面存 pair 类型变量,表示覆盖的区间。

每次将值为 \(r\) 的数的位置加入,在 set 中二分到与它相邻的区间,然后减去贡献,合并区间,加上新的贡献。

删除同理,将区间拆分,减去原先贡献,加上新的贡献即可。

复杂度 \(O(n\log n)\)。

代码有点长,但思路很清晰。

#include<bits/stdc++.h>
#define pii pair<int,int>
#define fir first
#define sec second
#define mkp make_pair 
using namespace std;
const int N=1e5+5;
int n,m,a[N],tmp[N],cnt;
vector<int>v[N];
set<pii >st;
int get(int l,int r){
	return (r-l+2)/2;
}
void ins(int w){
	set<pii >::iterator it2=st.lower_bound(mkp(w,0)),it=it2;
	int fl=0,fr=0;
	if(it2!=st.begin()){
		--it;
		if((*it).sec==w-1)fl=1;
	}if(it2!=st.end()&&(*it2).fir==w+1)fr=1;
	if(!fl&&!fr)++cnt,st.insert(mkp(w,w));
	else if(!fl&&fr){
		int r=(*it2).sec;
		if((r-w)%2==0)++cnt;
		st.erase(it2);
		st.insert(mkp(w,r));
	}else if(fl&&!fr){
		int l=(*it).fir;
		if((w-l)%2==0)++cnt;
		st.erase(it);
		st.insert(mkp(l,w));
	}else{
		int l=(*it).fir,r=(*it2).sec;
		cnt-=get(l,w-1)+get(w+1,r)-get(l,r);
		st.erase(it);st.erase(it2);st.insert(mkp(l,r));
	}
}
void del(int w){
	set<pii >::iterator it=st.upper_bound(mkp(w,1e9+1));--it;
	int l=(*it).fir,r=(*it).sec;
	if(w==r){
		cnt-=get(l,r)-get(l,r-1);
		st.erase(it);
		if(l<r)st.insert(mkp(l,r-1));
	}else if(w==l){
		cnt-=get(l,r)-get(l+1,r);
		st.erase(it);st.insert(mkp(l+1,r));
	}else{
		cnt-=get(l,r)-get(l,w-1)-get(w+1,r);
		st.erase(it);st.insert(mkp(l,w-1));st.insert(mkp(w+1,r));
	}
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;++i){
		cin>>a[i];
		tmp[i]=a[i];
	}
	sort(tmp+1,tmp+n+1);
	int p=unique(tmp+1,tmp+n+1)-(tmp+1);
	for(int i=1;i<=n;++i)a[i]=lower_bound(tmp+1,tmp+p+1,a[i])-tmp,v[a[i]].push_back(i);
	int l=1,r=0,ans=1e9;
	while(1){
		while(cnt<m&&r<p){
			++r;
			for(int i=0;i<v[r].size();++i)ins(v[r][i]);
		}
		if(cnt<m)break;
		ans=min(ans,tmp[r]-tmp[l]);
		for(int i=0;i<v[l].size();++i)del(v[l][i]);
		++l;
	}
	cout<<ans<<endl;
	return 0;
}

标签:tmp,get,int,题解,yLOI2022,幻世绘,st,mkp,it2
From: https://www.cnblogs.com/HQJ2007/p/17575778.html

相关文章

  • 题解链接
    积跬步,至千里tag:二分洛谷P1314聪明的质检员洛谷P1024一元三次方程求解tag:分块CF785EAntonandPermutationtag:贪心UVA1335/洛谷P4409皇帝的烦恼题解tag:倍增+贪心P4155、P6902——一类区间覆盖问题tag:二进制洛谷P7617KOMPIĆI的一个小tricktag:排列组合+......
  • 题解:【ICPC WF 2021 H】 Prehistoric Programs
    题目链接#include<bits/stdc++.h>#defineldlongdouble#defineuiunsignedint#defineullunsignedlonglong#defineintlonglong#defineebemplace_back#definepbpop_back#defineinsinsert#definempmake_pair#definepiipair<int,int>#def......
  • cf 题解
    MihaiandSlavicwerelookingatagroupof$n$frogs,numberedfrom$1$to$n$,allinitiallylocatedatpoint$0$.Frog$i$hasahoplengthof$a_i$.Eachsecond,frog$i$hops$a_i$unitsforward.Beforeanyfrogsstarthopping,SlavicandMihaicanp......
  • P7074 [CSP-J2020] 方格取数 题解
    题目:题目描述设有n*m 的方格图,每个方格中都有一个整数。现有一只小熊,想从图的左上角走到右下角,每一步只能向上、向下或向右走一格,并且不能重复经过已经走过的方格,也不能走出边界。小熊会取走所有经过的方格中的整数,求它能取到的整数之和的最大值。输入格式第一行有两个整......
  • AtCoder Beginner Contest 311 A-E题解
    A-FirstABC题意给一个长度为N的仅由ABC三个字符组成的字符串S,问S中ABC三个字符第一次出现的位置的最大值。题解使用map<char,bool>判重,记录当前不同的字符串的个数cnt,当cnt等于3时,输出此时的下标+1作为答案。Code#include<bits/stdc++.h>usingnamespacestd;usingll......
  • 第二次比赛部分题解
    P7060[NWRRC2014]AlarmClock  #include<bits/stdc++.h>usingnamespacestd;intmain(){intn;cin>>n;intarr[10]={6,2,5,5,4,5,6,3,7,6};boolcheck=false;//对于时间ab:cdfor(inta=0;a<=2;a++){//a最多可以到2(因为最大为23......
  • 2023“钉耙编程”中国大学生算法设计超级联赛(2)部分题解
    2023“钉耙编程”中国大学生算法设计超级联赛(2)部分题解7.201002 BinaryNumber可以发现,每个位置最多修改两次,再多了没有意义。当k为0时,无法修改直接输出。当n为1时,看k的奇偶性,若为奇数则将其翻转输出,否则直接输出。当n不为1时:如果给定的次数k小于序列中连续0串的个数,那一定......
  • P1833 樱花 题解
    二进制拆分做法:把每一个物品根据2的多少次方拆分,因为任何数都可以转化为二进制数核心思想:把每一个物品拆成很多个,分别计算价值和所需时间,再转化为01背包求解最后一点:完全背包可以把他的空间记为999999,不要太大,一般百万就足够了还有一点:cin和scanf不可以混用代码#include<bit......
  • P1679 神奇的四次方数 题解
    思路先枚举出\(n\)以内的4次方数然后dp.代码#include<bits/stdc++.h>#definelllonglong#defineldlongdouble#definemin(x,y)(x<y?x:y)usingnamespacestd;inlinevoidread(int&x){ x=0; shortflag=1; charc=getchar(); while(c<'0'......
  • P1757 通天之分组背包 题解
    思路分组背包模版题,不多说。代码#include<bits/stdc++.h>#definelllonglong#defineldlongdoubleusingnamespacestd;inlinevoidread(int&x){ x=0; shortflag=1; charc=getchar(); while(c<'0'||c>'9'){ if(c=='-......