首页 > 其他分享 >Codeforces 1876F - Indefinite Clownfish

Codeforces 1876F - Indefinite Clownfish

时间:2024-02-22 17:44:40浏览次数:21  
标签:get int mid up Codeforces Clownfish 序列 dw Indefinite

首先注意到这样一个性质:既然两个序列的平均值相同,并且又形成公差 \(\pm 1\) 的等差数列,就必然会存在一个元素 \(x\) 满足 \(x\) 在两个序列中都出现过(否则两个序列的值域区间不交,值域区间靠后的那个显然平均值比靠前的那个大)。那么我们枚举 \(x\) 在两个序列中出现的位置 \(p\) 和 \(q\)(\(p<q\))。当然,你直接枚举复杂度至少得 \(O(n^2)\) 了肯定爆掉了,考虑这样几个性质:

  • \((p,q)\) 中间所有被选择的元素要么属于上升序列,要么属于下降序列。不妨假设 \(p\) 属于上升序列,\(q\) 属于下降序列,如果中间同时有属于两个序列的元素,那么必然存在 \(a_s=x+1\) 属于上升序列,\(a_t=x+1\) 属于下降序列,那么如果 \(s,t\) 这个符合条件我们改枚举 \(x+1\) 就行了,否则肯定还有 \(a_u=a_v=x+2\),以此类推。也就是说我们加上这个限制是不影响答案的。
  • 不能存在 \(r\in(p,q)\) 满足 \(a_r=x\),否则根据上个结论,\((p,q)\) 中间选择的元素要么全部与 \(p\) 在同一个序列,要么全部与与 \(q\) 在同一个序列,不妨假设与 \(p\) 在同一个序列,那么我们把 \(q\) 的位置挪到 \(r\) 也是 ok 的,因为中间没有 \(q\) 所在的序列的元素,自然不影响这个序列的合法性。

换句话说,我们需要枚举的 \((p,q)\) 只有 \(O(n)\) 组,并且按照 \(p\) 属于上升还是下降序列 / 中间那一段是属于上升还剩下降序列总共可以分出四类:

  1. \(p\) 上升,\(q\) 下降,中间部分属于上升序列。
  2. \(p\) 上升,\(q\) 下降,中间部分属于下降序列。
  3. \(p\) 下降,\(q\) 上升,中间部分属于上升序列。
  4. \(p\) 下降,\(q\) 上升,中间部分属于下降序列。

但是这样问题又来了,中间的部分被强制要求属于同一个序列,这是好办的,但是 \(p\) 左边和 \(q\) 右边的部分是不确定的,而题目的限制条件又比较紧,尤其是那个选 \(k\) 个数的限制——对于这类题目,如果硬要 DP 那状态里必然要带记录一维选的数的个数,这就直接爆掉了。

考虑继续分析,设两个序列的最小最大值分别是 \(m_1,M_1,m_2,M_2\),那么题目的限制条件相当于 \(m_1+M_1=m_2+M_2\),并且还要求 \(M_1-m_1+M_2-m_2=k-2\),而第一个等式移个项就变成了 \(M_1-m_2=M_2-m_1\),故 \(M_1-m_2=\dfrac{k-2}{2}\)。而惊奇地我们发现,\(p\) 左边的部分的值域范围刚好是 \([m_1,M_2]\),\(q\) 右边的部分的值域范围刚好是 \([m_2,M_1]\)。也就是说左右两维实际上是独立的,只要满足 \(\dfrac{k-2}{2}\) 的限制就 ok 了。

于是思路就出来了,对这四种情况分别二分一下左右边界,然后倍增找到符合这种情况的上升和下降序列能够延申的上界和下界,然后看看上界和下界的差是否 \(\ge\dfrac{k-2}{2}\) 就行了。这样复杂度是 \(O(n\log^2n)\)。

const int MAXN=2e5;
const int LOG_N=18;
int n,k,a[MAXN+5];vector<int>occ[MAXN+5];
int getnxt(int x,int p){
	int pos=upper_bound(occ[x].begin(),occ[x].end(),p)-occ[x].begin();
	return occ[x][pos];
}
int getpre(int x,int p){
	int pos=lower_bound(occ[x].begin(),occ[x].end(),p)-occ[x].begin()-1;
	return occ[x][pos];
}
int Lup[LOG_N+2][MAXN+5],Ldw[LOG_N+2][MAXN+5],Rup[LOG_N+2][MAXN+5],Rdw[LOG_N+2][MAXN+5];
int get_lft_up(int x,int lim){for(int i=LOG_N;~i;i--)if(Lup[i][x]>=lim)x=Lup[i][x];return a[x];}
int get_lft_dw(int x,int lim){for(int i=LOG_N;~i;i--)if(Ldw[i][x]>=lim)x=Ldw[i][x];return a[x];}
int get_rit_up(int x,int lim){for(int i=LOG_N;~i;i--)if(Rup[i][x]<=lim)x=Rup[i][x];return a[x];}
int get_rit_dw(int x,int lim){for(int i=LOG_N;~i;i--)if(Rdw[i][x]<=lim)x=Rdw[i][x];return a[x];}
int main(){
	scanf("%d%d",&n,&k);if(k&1)return puts("-1"),0;
	for(int i=0;i<=n+1;i++)occ[i].pb(0);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]),occ[a[i]].pb(i);
	for(int i=0;i<=n+1;i++)occ[i].pb(n+1);
	int res=n+1;
	for(int i=1;i<=n;i++){
		Lup[0][i]=getpre(a[i]+1,i);Ldw[0][i]=getpre(a[i]-1,i);
		Rup[0][i]=getnxt(a[i]+1,i);Rdw[0][i]=getnxt(a[i]-1,i);
	}
	for(int i=1;i<=LOG_N;i++)for(int j=1;j<=n;j++){
		Lup[i][j]=(Lup[i-1][j]==0)?0:Lup[i-1][Lup[i-1][j]];
		Ldw[i][j]=(Ldw[i-1][j]==0)?0:Ldw[i-1][Ldw[i-1][j]];
		Rup[i][j]=(Rup[i-1][j]==n+1)?(n+1):Rup[i-1][Rup[i-1][j]];
		Rdw[i][j]=(Rdw[i-1][j]==n+1)?(n+1):Rdw[i-1][Rdw[i-1][j]];
	}
	for(int p=1;p<=n;p++){
		int q=getnxt(a[p],p);if(q==n+1)continue;
		int L,R,x,y;
		//p:up, q:down, mid:up
		x=y=-1;L=1,R=p;
		while(L<=R){
			int mid=L+R>>1;
			int up=get_lft_up(p,mid),dw=get_lft_dw(p,mid);
			if(up-dw>=k/2-1)x=mid,L=mid+1;
			else R=mid-1;
		}
		L=q,R=n;
		while(L<=R){
			int mid=L+R>>1;
			int up=get_rit_up(p,mid),dw=get_rit_dw(q,mid);
			if(up-dw>=k/2-1)y=mid,R=mid-1;
			else L=mid+1;
		}
		if(x!=-1&&y!=-1)chkmin(res,y-x);
		//p:up, q:down, mid:down
		x=y=-1;L=1,R=p;
		while(L<=R){
			int mid=L+R>>1;
			int up=get_lft_up(q,mid),dw=get_lft_dw(p,mid);
			if(up-dw>=k/2-1)x=mid,L=mid+1;
			else R=mid-1;
		}
		L=q,R=n;
		while(L<=R){
			int mid=L+R>>1;
			int up=get_rit_up(q,mid),dw=get_rit_dw(q,mid);
			if(up-dw>=k/2-1)y=mid,R=mid-1;
			else L=mid+1;
		}
		if(x!=-1&&y!=-1)chkmin(res,y-x);
		//p:down, q:up, mid:up
		x=y=-1;L=1,R=p;
		while(L<=R){
			int mid=L+R>>1;
			int up=get_lft_up(p,mid),dw=get_lft_dw(q,mid);
			if(up-dw>=k/2-1)x=mid,L=mid+1;
			else R=mid-1;
		}
		L=q,R=n;
		while(L<=R){
			int mid=L+R>>1;
			int up=get_rit_up(q,mid),dw=get_rit_dw(q,mid);
			if(up-dw>=k/2-1)y=mid,R=mid-1;
			else L=mid+1;
		}
		if(x!=-1&&y!=-1)chkmin(res,y-x);
		//p:down, q:up, mid:down
		x=y=-1;L=1,R=p;
		while(L<=R){
			int mid=L+R>>1;
			int up=get_lft_up(p,mid),dw=get_lft_dw(p,mid);
			if(up-dw>=k/2-1)x=mid,L=mid+1;
			else R=mid-1;
		}
		L=q,R=n;
		while(L<=R){
			int mid=L+R>>1;
			int up=get_rit_up(q,mid),dw=get_rit_dw(p,mid);
			if(up-dw>=k/2-1)y=mid,R=mid-1;
			else L=mid+1;
		}
		if(x!=-1&&y!=-1)chkmin(res,y-x);
	}
	if(res==n+1)puts("-1");
	else printf("%d\n",res);
	return 0;
}

标签:get,int,mid,up,Codeforces,Clownfish,序列,dw,Indefinite
From: https://www.cnblogs.com/tzcwk/p/18027842/Codeforces-1876F

相关文章

  • Codeforces Round 923 (Div. 3)
    A.MakeitWhite#include<bits/stdc++.h>usingnamespacestd;usingi32=int32_t;usingi64=longlong;usingi128=__int128;usingldb=longdouble;#defineinti64usingvi=vector<int>;usingpii=pair<int,int>;usingvii......
  • Codeforces Round 928 (Div. 4)
    CodeforcesRound928(Div.4)比赛链接A.VladandtheBestofFive思路就是统计字符A和字符B的个数,将个数多的那个输出出来Code#include<bits/stdc++.h>usingnamespacestd;#defineall(x)x.begin()+1,x.end()#defineintlonglongvoidsolve(){strings;......
  • Codeforces 1806E Tree Master
    考虑一个最基础的暴力,就是直接记忆化搜索暴力往上跳。但是能发现如果一层的节点数过多,状态数太多,就寄了。再考虑一个基础的暴力,就是直接跳。但是如果要跳的层数过多,就寄了。考虑结合一下,根号分治。对于一层内节点数\(\le\sqrt{n}\)的记录下每两个点间的答案。对于节点数......
  • Codeforces Round 928(Div. 4)
    Dashboard-CodeforcesRound928(Div.4)-Codeforces第一次参加CF,最后一道题连题都没读,下次不会就跳,菜是原罪A:找字符串中A,B数量,遍历一下最后比较即可B:判断是三角形还是正方形,题目表示除了正方形就是三角形,所以直接判断是不是正方形,用ans数组记录每一行1的个数,然后从大......
  • Codeforces Round 900 (Div. 3)
    题目A.只要k出现过就是YES#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongconstintN=1e5+10;#defineinf0x3f3f3f3fvoidsolve(){intn,k;cin>>n>>k;map<int,int>mp;for(inti=0,x;i<n;i++){cin......
  • Codeforces Round 928 (Div. 4) (小白的复盘)
    A.VladandtheBestofFive思路:给你一个长度字符串只包含A和B输出最多的字符解法:按题意来Code:#include<bits/stdc++.h>usingnamespacestd;intmain(){intt;cin>>t;while(t--){strings;cin>>s;intcnt=0;fo......
  • Codeforces Round 928 (Div. 4)(A、B、C、D、E、G)
    目录ABCDEGA统计A、B输出#include<bits/stdc++.h>#defineintlonglong#definerep(i,a,b)for(inti=(a);i<=(b);++i)#definefep(i,a,b)for(inti=(a);i>=(b);--i)#definepiipair<int,int>#definelllonglong#definedbdouble#de......
  • Codeforces Round 928 (Div. 4)
    总结一下最近:感觉过于追求进度了,没有好好的把每题都吃透消化,然后有点依赖题解了,没有好好的思考...B.VladandShapesB题输入二维数组的时候不可以直接两个for循环然后cin,要读入char,再转为数字赋值给二维数组,因为他读入的时候不带有空格而int是要有空格的,这样子比如读000就把它......
  • Codeforces Round 924 (Div. 2)
    目录写在前面ABCDEF写在最后写在前面比赛地址:https://codeforces.com/contest/1928。终于把欠下的一堆题补上了呃呃天使骚骚共通线什么构式呃呃,一周目就想走老师线直通单身笑死我了。A签到。发现等分后重新拼接可以得到\(\frac{x}{2}\times2y\)与\(\frac{y}{2}\times2......
  • Codeforces Round 927 (Div. 3)(A~F)
    目录ABCDEFA第一个遇到连续两个荆棘的地方就不能再赢金币了。所以统计连续两个荆棘之前的所有金币#include<bits/stdc++.h>#defineintlonglong#definerep(i,a,b)for(inti=(a);i<=(b);++i)#definefep(i,a,b)for(inti=(a);i>=(b);--i)#definepiipai......