P10192 题解
我们可以开一个
for(int i=1;i<=m;i++){
maxe=maxo=-1,mine=mino=INT_MAX;
for(int j=1;j<=k;j++){
scanf("%lld",&a[i][j]);
if(!(a[i][j]&1)) maxe=max(maxe,a[i][j]),mine=min(mine,a[i][j]);
else maxo=max(maxo,a[i][j]),mino=min(mino,a[i][j]);
}
if(maxe==-1) even[i]=-maxo,odd[i]=mino;
else if(maxo==-1) even[i]=mine,odd[i]=-maxe;
else even[i]=-maxo,odd[i]=-maxe;
}
有了这两个数组,我们就可以求一段区间内的最优解。
既然要字典序最小,那我们就要从前往后枚举,能选 Even 就选 Even,否则选 Odd。
如何判断能否选 Even?
如果当前的石子数量加上
这时我们就要用一个后缀和数组
判断能否选 Odd 同理。
如果两个都不能选,那么输出 -1 跑路。
Tips:计算 Even 的时候以为后面可以赚回来,石子数就可能会形成一个正数到负数再回到正数的过程,然后到了后面程序发现石子数为负了,就会输出 -1。感觉说的有点抽象,不懂的可以去看 #3 的倒数第二组手模一下。
for(int i=m;i>=1;i--)
suf[i]=min(0ll,suf[i+1]+max(even[i],odd[i]));//Tips
for(int i=1;i<=m;i++){
if(n+even[i]+suf[i+1]>0&&n+even[i]>0)
ans+="Even ",n+=even[i];
else if(n+odd[i]+suf[i+1]>0&&n+odd[i]>0)
ans+="Odd ",n+=odd[i];
else{
puts("-1"),flag=0;
break;
}
}