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;
}
posted @ 2020-09-21 23:03  BILL666  阅读(152)  评论(0编辑  收藏  举报