CSP-S 2020 贪吃蛇

7年OI一场空,一句assert见祖宗。 ### 题解 考虑一条蛇什么时候会叫停。

如果它吃了之后不是最小的,那么下一个吃了之后一定比它小(指以id为第二关键字后),死的一定比它早,那么可以直接吃,然后把问题交给下一条蛇即可。

如果吃了之后是最小的,那么下一个有可能吃它,那么它吃不吃就和下一条吃不吃相关,也就是和到之后第一次吃了不是最小的 的距离奇偶性相关了。

前面一部分显然满足后一个吃了之后比它小。后面(除了最后一次)也满足吃了之后会变成最小的。

那么再用一个队列,用类似「noip2016 蚯蚓」的方法维护即可。

时间复杂度\(O(n)\),并且在\(a_i\)不满足不降的情况下应该也是对的。

然而我加了个错误的assert,然后就挂了。

代码

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
#define x first
#define y second
int n;
int a[1000005];
namespace run{
	pii w1[1000005],w2[1000005];
	pii *l1,*r1,*l2,*r2;
	const pii inf(0x3f3f3f3f,0x3f3f3f3f),ind(-0x3f3f3f3f,-0x3f3f3f3f);
	pii mx1(){return l1<=r1?*l1:ind;}
	pii mn1(){return l1<=r1?*r1:inf;}
	pii mx2(){return l2<=r2?*l2:ind;}
	pii mn2(){return l2<=r2?*r2:inf;}
	int cnt,cur;
	bool add0(){
		if(~cur){cur^=1;}
		else{cur=0;}
		return 0;
	}
	bool add1(){
		if(~cur){cnt+=cur;return 1;}
		++cnt;return 0;
	}
	void solve(){
		l2=w2+1;r2=w2;
		l1=w1+1;r1=w1+n;
		for(int i=1;i<=n;++i){
			w1[n+1-i].x=a[i];w1[n+1-i].y=i;	
		}
		cnt=0;cur=-1;
		int s=n;
		while(s>1){
			pii mx,mn;
			if(mx1()>mx2()){mx=mx1();++l1;}
			else{mx=mx2();++l2;}
			if(mn1()<mn2()){mn=mn1();--r1;}
			else{mn=mn2();--r2;}
			mx.x-=mn.x;
			--s;
			//assert(mx<mn2()); 这里显然是错的,因为从最小变成不是最小的时候不一定比第二小小。
			if(s>1 && mx<min(mn1(),mn2())){
				if(add0())return;
			}
			else{
				if(add1())return;
			}
			*(++r2)=mx;
/*			if(add0())return;
			if(add1())return;*/
		}
	}
	bool main(){
		solve();
		printf("%d\n",n-cnt);
		return 0;
	}
}
int main(){
	freopen("snakes.in","r",stdin);
	freopen("snakes.out","w",stdout);
	int t;
	scanf("%d",&t);
	for(int id=1;id<=t;++id){
		if(id==1){
			scanf("%d",&n);
			for(int i=1;i<=n;++i)scanf("%d",a+i);
		}
		else{
			int k,x;
			scanf("%d",&k);
			for(;k;--k){
				scanf("%d",&x);	
				scanf("%d",a+x);
			}
		}
		run::main();
	}
	return 0;
}