LibreOJ 6515. 「雅礼集训 2018 Day10」贪玩蓝月【背包+栈+ST表+复杂度计算】
6515. 「雅礼集训 2018 Day10」贪玩蓝月
【题目描述】
【题解】
在线的做法,LOJ上有题解,就是开两个栈,记录前面插入和后面插入,用背包算出答案。
询问可以用ST表合并两个栈。
删除直接O(1)就可以了,但是如果其中一个栈删完了,那么我们将另一个栈取出一半放到左边重新背包计算,因为每次取出一半,所以复杂度是log级别的。
【代码如下】
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=50005;
typedef long long LL;
int n,MOD,Top[2],lg2[505];LL F[2][MAXN][505],S[505][11],INF;
struct xcw{int w,v;}Stk[2][MAXN];
#include<cctype>
int read(){
int ret=0;char ch=getchar();bool f=1;
for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');
for(; isdigit(ch);ch=getchar()) ret=ret*10+ch-'0';
return f?ret:-ret;
}
void Insert(int a,int x,xcw c){
Stk[a][x]=c;
for(int j=0;j<MOD;j++) F[a][x][j]=F[a][x-1][j];
for(int j=0,i;j<MOD;j++) i=(j+c.w>=MOD?j+c.w-MOD:j+c.w),F[a][x][i]=max(F[a][x][i],F[a][x-1][j]+c.v);
}
void Delete(int a){
if(Top[a]){Top[a]--;return;}int END=(Top[a^1]+1)>>1;
for(int i=1,j=END;i<=END;i++,j--) Insert(a,++Top[a],Stk[a^1][j]),Stk[a^1][j]=Stk[a^1][j+END];
Top[a^1]-=END;Top[a]=END-1;
for(int i=1;i<=Top[a^1];i++){xcw x=Stk[a^1][i];Insert(a^1,i,x);}
}
LL Ask(int L,int R){int K=lg2[R-L+1];return max(S[L][K],S[R-(1<<K)+1][K]);}
void Query(){
int L=read(),R=read();LL Ans=INF;
for(int i=0;i<MOD;i++) S[i][0]=F[1][Top[1]][i];
for(int j=1;j<=lg2[MOD];j++) for(int i=0;i+(1<<j)-1<MOD;i++) S[i][j]=max(S[i][j-1],S[i+(1<<j-1)][j-1]);
for(int i=0;i<MOD;i++)
if(F[0][Top[0]][i]>=0){
int l=L-i,r=R-i;if(l<0) l+=MOD;if(r<0) r+=MOD;
if(l<=r) Ans=max(Ans,F[0][Top[0]][i]+Ask(l,r));else Ans=max(Ans,F[0][Top[0]][i]+max(Ask(0,r),Ask(l,MOD-1)));
}
printf("%lld\n",Ans<0?-1:Ans);
}
int main(){
read();n=read(),MOD=read();
for(int i=2;i<=MOD;i++) lg2[i]=lg2[i>>1]+1;
memset(F,192,sizeof(F)),INF=F[0][0][0],F[0][0][0]=F[1][0][0]=0;
for(int i=1;i<=n;i++){
char ch[10];scanf("%s",ch);
if(ch[0]=='I') Insert(ch[1]=='G',++Top[ch[1]=='G'],(xcw){read()%MOD,read()});else
if(ch[0]=='D') Delete(ch[1]=='G');else Query();
}
return 0;
}