CSP-S2020 贪吃蛇

题目描述


题解

70分没想清楚+时间不够=20分

考场上的奇妙做法:

假设每条蛇都没有脑子,不管自己的死活往下吃,那么最后会形成一棵操作树,(u,v,t)表示u在t时间吃了v

显然根不会被吃,所以其相连的有危险,所以它们会放掉自己儿子中时间最大的那个,设其为y父亲为x,则非x外的蛇知道y是最大的,所以如果它们不放的话x必须要放,x也知道别的蛇不会放,所以它也会放了y,并且这样对所有有危险的蛇都是最优的

然后有一部分蛇会脱离危险,所以它们可以继续往下吃,如此用前缀和优化一下随便维护即可做到O(n)

问题是怎么O(n)求出操作树,具体见https://blog.csdn.net/EI_Captain/article/details/109552980

换一种做法(Orz lk),如果一条蛇吃完后不会变成最小的则它一定会吃,因为下一条蛇吃了之后会比自己更小,死得比自己快,所以把锅丢给它

如果变成最小的,那么往后找出按照这样吃第一条不会变成最小的蛇,那么它一定会吃,下一条一定不吃,下下条一定会吃,按照奇偶性讨论

用两个队列即可维护,只要没有出现变成最小的话那么max递减min递增,相减得到的递减丢到第二个队列里

如果变成最小的,那么每次只能跑到末尾否则就停

时间复杂度O(n)

code

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define ll long long
#define file
using namespace std;

struct type{int s,x;} s1,s2;
struct Queue{type d[1000001];int h,t;
	void push(type s) {d[++t]=s;}
	void pop(bool tp) {if (!tp) ++h; else --t;}
	void clear() {h=1,t=0;}
	bool empty() {return h>t;}
	type head() {return d[h];}
	type tail() {return d[t];}
} q[2];
int a[1000001],T,n,i,j,k,l,I,x,y,ans,I1,I2,sum;

bool operator < (type a,type b) {return a.s<b.s || a.s==b.s && a.x<b.x;}
bool operator > (type a,type b) {return a.s>b.s || a.s==b.s && a.x>b.x;}
void swap(int &x,int &y) {int z=x;x=y;y=z;}

int main()
{
//	freopen("snakes.in","r",stdin);
//	#ifdef file
//	freopen("snakes.out","w",stdout);
//	freopen("b.out","w",stdout);
//	#endif
	
	scanf("%d",&T);
	fo(I,1,T)
	{
		if (I==1)
		{
			scanf("%d",&n);
			fo(i,1,n) scanf("%d",&a[i]);
		}
		else
		{
			scanf("%d",&k);
			fo(i,1,k) scanf("%d%d",&x,&y),a[x]=y;
		}
		
		q[0].clear(),q[1].clear(),ans=n;
		I1=0,I2=1;
		fd(i,n,1) q[I1].push(type{a[i],i});
		while (ans>1)
		{
			--ans;
			if (q[I2].empty() || q[I1].tail()<q[I2].tail()) s2=q[I1].tail(),q[I1].pop(1); else s2=q[I2].tail(),q[I2].pop(1);
			if (!s2.s) continue;
			if (q[I2].empty() || q[I1].head()>q[I2].head()) s1=q[I1].head(),q[I1].pop(0); else s1=q[I2].head(),q[I2].pop(0);
			
			s1.s-=s2.s;
			if (q[I1].empty()) swap(I1,I2);
			q[I2].push(s1);
			if (q[I1].tail()>s1) break;
		}
		if (ans>1)
		{
			sum=0;
			while (sum<ans-1)
			{
				if (q[I2].empty() || q[I1].tail()<q[I2].tail()) s2=q[I1].tail(),q[I1].pop(1); else s2=q[I2].tail(),q[I2].pop(1);
				if (q[I2].empty() || q[I1].head()>q[I2].head()) s1=q[I1].head(),q[I1].pop(0); else s1=q[I2].head(),q[I2].pop(0);
				
				s1.s-=s2.s;
				if (q[I1].empty()) swap(I1,I2);
				if (!q[I1].empty() && q[I1].tail()<s1 || !q[I2].empty() && q[I2].tail()<s1) break;
				q[I2].push(s1);
				++sum;
			}
			sum+=sum==(ans-1);
			ans+=!(sum&1);
		}
		
		printf("%d\n",ans);
	}
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}
posted @ 2020-11-10 21:18  gmh77  阅读(543)  评论(0编辑  收藏  举报