Mole solution
solution Mole
subtask1
纯暴力
subtask2
考虑
full task
考虑优化检验到
考虑基于前一次推。
对于每一轮检验,设
对于一种可行方案,当且仅当
充分性证明:
假设
则在窗口离开之后
必要性证明:
(不存在要取的数时直接取走)
否则,
使用线段树维护区间加,并查集或线段树二分维护某位置后面第一个零。
假设插入一个数之后
维护存在性,设
线段树初始化为
考虑任意时间,对当前情况下的时间加一,将最后一位新加入的加进堆,
将
由于每次加一处理完后都无法再次插入任何数,因此并查集维护的最后一个零其实就位于当前段末尾。
使用线段树和堆维护即可。
正常维护加一次取数即可,(时间轴上的每次移动最多取数一次)
和上面 subtask3 同理,中途被毙掉的数以后也不会选。
核心代码:
int n;
struct cmp{
__attribute__((always_inline)) bool operator () (pair<int,int> a,pair<int,int> b)
{
return a.second<b.second;
}
};
priority_queue<pair<int,int>,vector<pair<int,int> >,cmp> q;
int tree[10000005];
int tag[10000005];
void update(int now)
{
tree[now]+=tag[now];
tag[(now<<1)]+=tag[now];
tag[(now<<1)+1]+=tag[now];
tag[now]=0;
}
bool getmin(int x,int y,int now=1,int f=1,int l=n)//区间是否存在0
{
if(f>=x&&l<=y) return tree[now]+tag[now];
update(now);
bool fl=1;
if(((f+l)>>1)+1<=y) fl=getmin(x,y,(now<<1)+1,((f+l)>>1)+1,l);
if(!fl) return 0;
if(((f+l)>>1)>=x) fl=getmin(x,y,(now<<1),f,((f+l)>>1));
return fl;
}
void pls(int num,int x,int y,int now=1,int f=1,int l=n)//区间加
{
if(f>=x&&l<=y)
{
tag[now]+=num;
return ;
}
update(now);
if(((f+l)>>1)+1<=y) pls(num,x,y,(now<<1)+1,((f+l)>>1)+1,l);
if(((f+l)>>1)>=x) pls(num,x,y,(now<<1),f,((f+l)>>1));
tree[now]=min(tree[(now<<1)]+tag[(now<<1)],tree[(now<<1)+1]+tag[(now<<1)+1]);
}
int main()
{
input();
int i;int l;int rd;
long long ans=0;
long long pr=0;
pair<int,int> fl;
l=read(),n=read();
for(i=1;i<l;i++)
{
rd=read();
if(rd>0) q.push(pair<int,int>{i,rd});
}
for(i=l;i<=n;i++)
{
rd=read();
if(rd>0) q.push(pair<int,int>{i,rd});
pls(1,i-l+1,i);
while(!q.empty())
{
fl=q.top();
if(getmin(fl.first,i))
{
pls(-1,fl.first,i);
if(fl.second>0) ans+=fl.second,fl.second--,q.push(fl);;
q.pop();
break;
}
q.pop();
}
write(ans),putchar(' ');
}
output();
return 0;
}