【描述】
现在我们有若干种事件和询问,如下所示:
IF w v:在前端加入一件特征值为 w 战斗力为 v 的装备
IG w v:在后端加入一件特征值为 w 战斗力为 v 的装备
DF:删除最前端的装备
DG:删除最后端的装备
QU l r:在当前的装备中选取若干装备,他们的和对 p 取模后在 [l,r] 中,使得这些装备的战斗力之和最大
【思路】
如果只有一边插入删除,那么我们可以用一个栈来维护这个背包dp。可是我们要支持在两端操作,所以我们可以维护两个栈。
1.插入:根据方向直接在第一个栈或第二个栈插入
2.删除:在第一个栈或第二个栈删除,如果有一个栈空了,我们暴力把另一个栈的取出来,两个栈平均分配一下物品,重新暴力插入两个栈即可。注意特判只有一个物品的情况。
3.询问:我们需要合并两个栈的dp信息,这可以使用单调队列实现。
除此之外,这道题有线段树分治做法。
代码:
#include<bits/stdc++.h>
#define re register
#define mp make_pair
using namespace std;
const int M=5e2+5,N=2.5e4+5;
inline int red(){
int data=0;bool w=0; char ch=getchar();
while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
if(ch=='-') w=1,ch=getchar();
while(ch>='0' && ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
return w?-data:data;
}int n,m,c,mod;
typedef long long ll;
typedef pair<int,int>T;
inline int id(int x){
if(x<0)x+=mod;
else if(x>=mod)x-=mod;
return x;
}
inline ll max(const ll&a,const ll&b){return a>b?a:b;}
struct stk{
T a[N];int top;
ll dp[N][M];
void prework(){top=0;for(int re i=1;i<mod;i++)dp[0][i]=-1e16;dp[0][0]=0;}
inline void push(T x){
int w=x.first%mod,v=x.second;
a[++top]=mp(w,v);
for(int re i=0;i<mod;++i)
dp[top][i]=max(dp[top-1][i],dp[top-1][id(i-w)]+v);
}
}s1,s2;
T rb[N];
inline void rebuild(){
int cnt=0;
for(int re i=s1.top;i>0;--i)rb[++cnt]=s1.a[i];
for(int re i=1;i<=s2.top;++i)rb[++cnt]=s2.a[i];
int cnt1=cnt>>1;s1.top=0,s2.top=0;
for(int re i=cnt1;i>0;i--)s1.push(rb[i]);
for(int re i=cnt1+1;i<=cnt;++i)s2.push(rb[i]);
}
int q[N],L=1,R=0;
ll *a,*b;
inline void cmax(ll&x,const ll&y){(x<y)&&(x=y);}
inline ll query(int l,int r){
L=1;R=0;
int len=r-l+1;ll ans=-1;
a=s1.dp[s1.top];b=s2.dp[s2.top];
for(int re i=0;i<len;++i){
while(L<=R&&a[i]>=a[q[R]])R--;
q[++R]=i;cmax(ans,a[q[L]]+b[id(r-i)]);
}for(int re i=len;i<mod;++i){
while(L<=R&&q[L]<=i-len)L++;
while(L<=R&&a[i]>=a[q[R]])R--;
q[++R]=i;cmax(ans,a[q[L]]+b[id(r-i)]);
}for(int re i=mod-len;i<mod;++i){
while(L<=R&&q[L]<i)L++;
cmax(ans,a[q[L]]+b[id(l-i)]);
}return ans;
}
char s[5];
int main()
{
red();m=red();mod=red();
s1.prework();s2.prework();
while(m--){
scanf("%s",s);
switch(s[0]){
case'I':{
int a=red(),b=red();
switch(s[1]){
case'F':{s1.push(mp(a,b));break;}
case'G':{s2.push(mp(a,b));break;}
break;
}break;
}
case'D':{
switch(s[1]){
case'F':{if(!s1.top)rebuild();s1.top?s1.top--:s2.top--;break;}
case'G':{if(!s2.top)rebuild();s2.top?s2.top--:s1.top--;break;}
}break;
}
case'Q':{
int a=red(),b=red();
cout<<query(a,b)<<"\n";
break;
}
}
}
}