题目大意
题解
这题考场上一看就感觉很可做,非常快就想到了简单又自然的70分方法,但是将大量的时间都放在了想办法优化到满分上,导致T3都没时间想。
做法不难,容易发现,如果当前的(Max)吃掉(Min)以后不是最小的,那么一定可以吃,因为下一个吃完以后一定会比他小,也就是会先被吃掉,所以只需要把问题交给下一条蛇就行了。
然后可以发现,如果当前吃完以后变成最小的了,那么就要看下一个会不会选择吃掉它,而下一个又要再需要继续看接下来的蛇的操作。
容易总结出一条结论,当现在吃完以后变成最小的以后,只需要判断第一个吃完不是最小的蛇与当前轮数的奇偶性就行了。
然后接下来的问题就比较简单了,可以用两个队列来维护。一个队列维护还未被操作的蛇,一个队列维护已经操作后的蛇,两个队列都是单调的,就可以以此来维护(Max)和(Min)了。
当只剩两条蛇的时候要特判,此时显然是可以吃的。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 3000010
using namespace std;
int T,n,i,k,x,y,ans,l,r,l1,r1;
struct node{
int val,id;
}lp[N],a[N],p[N];
inline int read(){
int x=0;
char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x;
}
int cmp(node x,node y){
if (x.val!=y.val) return x.val>y.val;
return x.id>y.id;
}
node getmax(){
if (l>r) return p[l1++];
if (l1>r1) return a[l++];
if (cmp(a[l],p[l1])) return a[l++];
else return p[l1++];
}
node getmin(){
if (l>r) return p[r1--];
if (l1>r1) return a[r--];
if (cmp(a[r],p[r1])==0) return a[r--];
else return p[r1--];
}
node getmin2(){
if (l>r) return p[r1];
if (l1>r1) return a[r];
if (cmp(a[r],p[r1])==0) return a[r];
else return p[r1];
}
void solve(){
l=1,r=n,l1=1,r1=0;
int tot;
node Max,Min;
ans=n;
while (true){
if (ans<=2){
ans=1;
return;
}
Max=getmax();
Min=getmin();
Max.val-=Min.val;
if (cmp(Max,getmin2())==0){
tot=1;
p[++r1]=Max;
while (true){
if (ans-tot<=2) {
tot++;
if (tot%2==1) ans--;
return;
}
Max=getmax();
Min=getmin();
Max.val-=Min.val;
tot++;
if (cmp(Max,getmin2())){
if (tot%2==1) ans--;
return;
}
else
p[++r1]=Max;
}
}
else{
ans--;
p[++r1]=Max;
}
}
}
int main(){
freopen("snakes.in","r",stdin);
freopen("snakes.out","w",stdout);
T=read();
n=read();
for (i=1;i<=n;i++) lp[i].val=read(),lp[i].id=i;
for (i=1;i<=n/2;i++) swap(lp[i],lp[n-i+1]);
for (i=1;i<=n;i++) a[i]=lp[i];
solve();
printf("%d
",ans);
T--;
while (T--){
k=read();
for (i=1;i<=k;i++) x=read(),y=read(),lp[n-x+1].val=y;
for (i=1;i<=n;i++) a[i]=lp[i];
solve();
printf("%d
",ans);
}
return 0;
}