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;
} 
posted @ 2019-02-23 14:44  XSamsara  阅读(270)  评论(0编辑  收藏  举报