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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM