[luogu7078]贪吃蛇
结论:若$a_{n}-a_{1}\ge a_{2}$,那么一定会吃掉
证明:分类讨论,若$a_{n-1}$也吃掉了$a_{2}$,就说明$a_{n-1}$之后不会被吃掉,而$a_{n-1}-a_{2}\le a_{n}-a_{1}$,因此$a_{n}$也不会被吃掉;若$a_{n-1}$不吃$a_{2}$,那么$a_{n}$同样也不会被吃掉
(注意,这只是说明满足这一条件下一定会吃,而不是吃一定要满足此条件)
根据这个结论,可以模拟直至$a_{n}-a_{1}<a_{2}$
考虑接下来是否会吃,如果有$a_{n-1}-(a_n-a_{1})\ge a_{2}$,那么一定不会吃(吃了$a_{n-1}$就一定可以吃他),类似的,如果$a_{n-1}-a'_{1}<a_{2}$且$a_{n-2}-a''_{1}\ge a_{2}$,那么一定可以吃(因为$a_{n-1}$一定不会吃)……
换言之,$a_{n}$吃掉$a_{1}$当且仅当下一次出现$a_{n'}-a_{1}\ge a_{2}$时$n$与$n'$同奇偶,正确性可以归纳得到,同时下一次$n-1$与$n'$就不同奇偶了,即不能吃掉
如何维护这个过程,对两部分分别维护:
1.对于第一部分,即每一次都有$a_{n}-a_{1}<a_{2}$,将所有点分为经过操作和未经过操作两部分,根据上面证明的过程,越晚经过操作的越小,因此用一个队列维护两部分,最小值和最大值都可以得到
2.对于第二部分,直接令$a_{1}=a_{n}-a_{1}$即可(当然要判断一下)
还有一些特殊情况,主要是关于$n=2$时的判断
1.对于第一部分,即模拟直到$a_{n}-a_{1}<a_{2}$,若最终$n=2$,则答案为1(可证一定有$a_{n}\ge \sum_{i=1}^{n-1}a_{i}$);
2.对于第二部分,即模拟直到$a_{n}-a_{1}\ge a_{2}$,若最终$n'=1$,令$n'=2$
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 1000005 4 #define fi first 5 #define se second 6 set<pair<int,int> >s; 7 deque<pair<int,int> >q1,q2; 8 int t,n,m,x,y,a[N]; 9 pair<int,int> b[N]; 10 int calc(int n){ 11 q1.clear(),q2.clear(); 12 for(int i=1;i<=n;i++)q1.push_back(make_pair(a[i],i)); 13 pair<int,int>x,y,z; 14 while (1){ 15 if (n==2)return 1; 16 if ((q2.empty())||(q1.back()>q2.back())){ 17 x=q1.back(); 18 q1.pop_back(); 19 } 20 else{ 21 x=q2.back(); 22 q2.pop_back(); 23 } 24 y=q1.front(); 25 q1.pop_front(); 26 z=make_pair(x.fi-y.fi,x.se); 27 if (((q1.empty())||(q1.front()>z))&&((q2.empty())||(q2.front()>z))){ 28 q1.push_front(y); 29 q1.push_back(x); 30 break; 31 } 32 n--; 33 q2.push_front(z); 34 } 35 int nn=0; 36 while ((!q1.empty())||(!q2.empty())) 37 if ((!q1.empty())&&((q2.empty())||(q1.front()<q2.front()))){ 38 b[++nn]=q1.front(); 39 q1.pop_front(); 40 } 41 else{ 42 b[++nn]=q2.front(); 43 q2.pop_front(); 44 } 45 while (nn>2){ 46 x=make_pair(b[nn].fi-b[1].fi,b[nn].se); 47 if (x>=b[2])break; 48 b[1]=x; 49 nn--; 50 } 51 return n-((n&1)==(nn&1)); 52 } 53 int main(){ 54 scanf("%d%d",&t,&n); 55 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 56 printf("%d\n",calc(n)); 57 t--; 58 while (t--){ 59 scanf("%d",&m); 60 for(int i=1;i<=m;i++){ 61 scanf("%d%d",&x,&y); 62 a[x]=y; 63 } 64 printf("%d\n",calc(n)); 65 } 66 return 0; 67 }