LOJ#6515. 「雅礼集训 2018 Day10」贪玩蓝月
题意:
给出一个双端队列,每次进行操作:
- 在队首插入二元组(w,v)
- 在队尾插入二元组(w,v)
- 删除队首元素
- 删除队尾元素
每次询问给定l,r,求在当前双端队列中选择一个子集S使得\(\sum_{(w,v)\in S}w\) mod \(p\in[l,r]\),且求\(\sum_{(w,v)\in S}v\)的最大值
数据范围:
操作数m<=5e4,模数p<=500
题解:
容易发现我们要维护的一个东西其实就是背包
我们可以用两个栈来模拟题中所描述的双端队列,其中一个前面插入,另外一个后面插入
每次新插入一个值后就更新一下背包
对于删除,如果这个栈非空,直接把栈顶弹掉走人
否则把另一个栈搞一半过来,暴力重做一次背包(为了维护复杂度)
对于询问直接用ST表求区间最大值即可(具体详见代码)
p.s.其实也可以直接用单调队列来做,但是懒得了。。。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
const int N=5e4+5,M=505;
int m,p;
int top[2],lg[M];
pll t[2][N];
ll f[2][N][M],inf,st[M][10];
inline int read()
{
int s=0,w=1; char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')w=-1;
for(;isdigit(ch);ch=getchar())s=(s<<1)+(s<<3)+(ch^48);
return s*w;
}
inline void pre()
{
memset(f,128,sizeof(f));
inf=-f[0][0][0];
f[0][0][0]=f[1][0][0]=0;
lg[1]=0;for(int i=2;i<=p;++i)lg[i]=lg[i>>1]+1;
}
inline void ins(bool tp,int pos,pll mp)
{
t[tp][pos]=mp;
for(int i=0;i<p;++i)f[tp][pos][i]=f[tp][pos-1][i];
for(int i=0;i<p;++i)
f[tp][pos][(i+mp.first)%p]=max(f[tp][pos][(i+mp.first)%p],f[tp][pos-1][i]+mp.second);
}
inline void del(bool tp)
{
if(top[tp]){--top[tp];return;}
static pll old[N];int num=top[tp^1];
for(int i=1;i<=num;++i)old[i]=t[tp^1][i];
int mid=num+1>>1;
for(int i=1;i<=mid;++i)t[tp][mid-i+1]=old[i];
for(int i=mid+1;i<=num;++i)t[tp^1][i-mid]=old[i];
top[tp]=mid-1,top[tp^1]=num-mid;
for(int i=1;i<=top[tp];++i)ins(tp,i,t[tp][i]);
for(int i=1;i<=top[tp^1];++i)ins(tp^1,i,t[tp^1][i]);
}
inline ll query(int l,int r)
{
int len=lg[r-l+1];
return max(st[l][len],st[r-(1<<len)+1][len]);
}
inline ll solve(int l,int r)
{
ll ans=-inf;
for(int i=0;i<p;++i)st[i][0]=f[0][top[0]][i];
for(int i=1;i<=lg[p];++i)
for(int j=0;j+(1<<i)<=p;++j)
st[j][i]=max(st[j][i-1],st[j+(1<<(i-1))][i-1]);
for(int i=0;i<p;++i)
{
if(f[1][top[1]][i]<0)continue;
int L=l-i,R=r-i;
L=(L+p)%p,R=(R+p)%p;
if(L<=R)ans=max(ans,f[1][top[1]][i]+query(L,R));
else ans=max(ans,f[1][top[1]][i]+max(query(L,p-1),query(0,R)));
}
return ans<0?-1:ans;
}
int main()
{
read();
m=read(),p=read();
pre();
char opt[5];
while(m--)
{
scanf("%s",opt);
if(opt[0]=='I')
{
ll w=1ll*read(),v=1ll*read();
ins(opt[1]=='G',++top[opt[1]=='G'],make_pair(w%p,v));
}
else if(opt[0]=='D')del(opt[1]=='G');
else
{
int l=read(),r=read();
printf("%lld\n",solve(l,r));
}
}
return 0;
}
NO PAIN NO GAIN