1. 程式人生 > 其它 >P7078-[CSP-S2020]貪吃蛇【貪心,佇列】

P7078-[CSP-S2020]貪吃蛇【貪心,佇列】

正題

題目連結:https://www.luogu.com.cn/problem/P7078


題目大意

\(n\)條貪吃蛇,第\(i\)條長度為\(a_i\),每次最長的那條蛇可以選擇吃掉最短的那條蛇,然後自己的長度減去其長度,也可以不吃然後結束遊戲。

現在詢問在所有蛇都希望吃的蛇最多且自己不會被吃的情況下最後會留下多少條蛇。

\(T\)次每次修改\(k\)個值,保證修改前後\(a\)單調不降。

\(3\leq n\leq 10^6,1\leq T\leq 10,0\leq k\leq 10^5\)


解題思路

考慮一條蛇什麼時候會選擇不吃。

首先如果一條蛇吃掉別的蛇之後它不是最小的蛇,那麼它一定會去吃這條蛇。假設最大的和次大的蛇長度為\(a,b\)

,最小和次小的為\(c,d\),由於\(a-c>d\)又有\(b-d<a-c\)那麼顯然如果\(b\)蛇吃了肯定會比\(a\)蛇先死,那麼如果\(b\)會死那麼它肯定不吃\(d\)那麼\(a\)蛇顯然也不會被吃。

如果一條蛇吃了別的蛇後它是最小的蛇會發生什麼。記蛇從大到小排序為\(a,b,c,...\),那麼如果蛇\(a\)吃了最小的後它成最小的了且\(b\)會吃,那麼\(a\)肯定不吃。此時我們就需要判斷\(b\)是否吃了,同理的,如果\(b\)吃了最小的之後它也是最小的那麼就需要考慮\(c\)吃不吃最小的。

此時遞迴下去直到一條吃了之後不是最小的或者只剩兩條蛇時就結束了。

然後用類似於合併果子那樣的方法用兩個佇列維護即可。

時間複雜度:\(O(Tn)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
using namespace std;
const int N=1e6+10;
int T,n,a[N],w[N],q1[N],q2[N];
int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-f;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
bool cmp(int x,int y)
{return (w[x]==w[y])?x<y:w[x]<w[y];}
void solve(){
	int h1=1,t1=n,h2=1,t2=0,v,p;T--;
	for(int i=1;i<=n;i++)w[q1[n-i+1]=i]=a[i];
	while(1){
		if(t1-h1+1+t2-h2+1==2){printf("%d\n",1);return;}
		if(t2-h2+1<=0||t1-h1+1>0&&cmp(q2[h2],q1[h1])){
			v=w[p=q1[h1]];p=q1[h1];h1++;
			if(t2-h2+1<=0||t1-h1+1>0&&cmp(q1[t1],q2[t2]))v-=w[q1[t1]],t1--;
			else v-=w[q2[t2]],t2--;
		}
		else{
			v=w[p=q2[h2]];h2++;
			if(t2-h2+1<=0||t1-h1+1>0&&cmp(q1[t1],q2[t2]))v-=w[q1[t1]],t1--;
			else v-=w[q2[t2]],t2--;
		}
		w[p]=v;
		if((t2-h2+1<=0||cmp(p,q2[t2]))&&(t1-h1+1<=0||cmp(p,q1[t1])))
			{q2[++t2]=p;break;}
		q2[++t2]=p;
	}
	int cnt=0,f=t2-h2+1+t1-h1+1;
	while(1){
		cnt++;
		if(t1-h1+1+t2-h2+1==2){printf("%d\n",f+(cnt&1));return;}
		if(t2-h2+1<=0||t1-h1+1>0&&cmp(q2[h2],q1[h1])){
			v=w[p=q1[h1]];p=q1[h1];h1++;
			if(t2-h2+1<=0||t1-h1+1>0&&cmp(q1[t1],q2[t2]))v-=w[q1[t1]],t1--;
			else v-=w[q2[t2]],t2--;
		}
		else{
			v=w[p=q2[h2]];h2++;
			if(t2-h2+1<=0||t1-h1+1>0&&cmp(q1[t1],q2[t2]))v-=w[q1[t1]],t1--;
			else v-=w[q2[t2]],t2--;
		}
		w[p]=v;
		if((t2-h2+1<=0||cmp(p,q2[t2]))&&(t1-h1+1<=0||cmp(p,q1[t1])))
			{q2[++t2]=p;continue;}
		printf("%d\n",f+(cnt&1));return;
	}
	return;
}
int main()
{
	T=read();n=read();
	for(int i=1;i<=n;i++)a[i]=read();
	solve();
	while(T){
		int k=read();
		while(k--){
			int x=read(),w=read();
			a[x]=w;
		}
		solve();
	}
	return 0;
}