CF732D
今上午的模拟赛考了这道题,改了一下题面。
本来切掉了,考场源码交到 CF 上也过了,但是因为你教师机评测太牛逼硬是把我代码判错了,现在也不是很理解为什么。
用了一种和大多数人不一样的方法。
首先考虑什么时候无解。
显然,越晚攻击一个敌人,就越有可能击败他。也就是说,如果我们让所有敌人在最后出现时刻时被攻击,仍不能击败所有人,那么无解。
然后我们再考虑如何取最优答案。
让所有人在最后时刻被击败肯定是最劣的一种答案,那么想要使答案尽可能优,肯定要每次找出最后一个被消灭的敌人,使他的出现时刻变成上一个,再尝试能否全部击败。
接着考虑一下,移动一个敌人会产生什么影响。
我们先记录最劣情况下到每个时刻的士兵数量。
假设我们最后出现的敌人位置为 \(x\),这个敌人的上一个出现位置是 \(y\),消灭这个敌人需要花费 \(v\) 的士兵。
那么我们把这个士兵从 \(x\) 移走,显然 \([x,n]\) 位置的士兵数要在现在的基础上加 \(v+1\) 个(攻击花费的 \(v\) 个与走到 \(x\) 位置时新增的 \(1\) 个)。
然后我们把这个士兵插入到位置 \(y\),那么 \([y,n]\) 的士兵数要在现在的基础上减去 \(v+1\) 个,理由同上。
如何判断移动这个士兵合不合法呢?只需要判断减去这个值之后,\([y,n]\) 位置有没有出现负数即可,原因显然。具体操作时可以求出 \([y,n]\) 位置的最小值,判断一下是否大于等于 \(v+1\)。
所以我们只需要对序列进行区间加和区间求最小值两种操作,上线段树即可。
bool vis[maxn];
int n,m,tot,Ans,all,a[maxn];
int lst[maxn],ck[maxn];
int pos[maxn],val[maxn];
deque<int> id[maxn];
struct node{int a,b;};
deque<node> q;
namespace Seg{
#define ls x<<1
#define rs x<<1|1
int minx[maxn<<2],lazy[maxn<<2];
void pushup(int x){
minx[x]=min(minx[ls],minx[rs]);
}
void pushdown(int x){
if(lazy[x]==0) return;
lazy[ls]+=lazy[x];lazy[rs]+=lazy[x];
minx[ls]+=lazy[x];minx[rs]+=lazy[x];
lazy[x]=0;
}
void build(int x,int l,int r){
if(l==r){
minx[x]=a[l];
return;
}
int mid=l+r>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(x);
}
void update1(int x,int l,int r,int L,int R,int val){
if(L<=l&&R>=r){
minx[x]+=val;
lazy[x]+=val;
return;
}
int mid=l+r>>1;pushdown(x);
if(L<=mid) update1(ls,l,mid,L,R,val);
if(R>=mid+1) update1(rs,mid+1,r,L,R,val);
pushup(x);
}
int query(int x,int l,int r,int L,int R){
if(L<=l&&R>=r) return minx[x];
int mid=l+r>>1,ans=INF;pushdown(x);
if(L<=mid) ans=min(ans,query(ls,l,mid,L,R));
if(R>=mid+1) ans=min(ans,query(rs,mid+1,r,L,R));
return ans;
}
}
signed main(){
n=read(); m=read();
for(int i=1;i<=n;i++){
pos[i]=read();
if(pos[i]){
id[pos[i]].push_front(i);
q.push_front((node){i,pos[i]});
}
}
for(int i=n;i>=1;i--){
if(!vis[pos[i]]||!pos[i]){
vis[pos[i]]=1;
if(pos[i]) lst[i]=pos[i],id[pos[i]].pop_front(),Ans=max(Ans,i);
}
else lst[i]=0;
}
for(int i=1;i<=m;i++) val[i]=read();
for(int i=1;i<=n;i++){
if(lst[i]){
all++;
tot-=val[lst[i]];
if(tot<0) return puts("-1"),0;
}
else tot++;
a[i]=tot;
}
if(all<m) return puts("-1"),0;
Seg::build(1,1,n);
while(1){
if(q.size()==m) break;
node P=q.front();q.pop_front();
int fir=P.a,sec=P.b;
int nxt_pos=id[sec].front();
id[sec].pop_front();
Seg::update1(1,1,n,fir,n,1+val[sec]);
int minx=Seg::query(1,1,n,nxt_pos,n);
if(minx<1+val[sec]||minx>=INF) return printf("%d\n",Ans),0;
Seg::update1(1,1,n,nxt_pos,n,-1-val[sec]);Ans=q.front().a;
}
printf("%d\n",Ans);
return 0;
}