zoukankan      html  css  js  c++  java
  • LOJ#6515. 「雅礼集训 2018 Day10」贪玩蓝月

    题目链接

    题意:

    给出一个双端队列,每次进行操作:

    • 在队首插入二元组(w,v)
    • 在队尾插入二元组(w,v)
    • 删除队首元素
    • 删除队尾元素

    每次询问给定l,r,求在当前双端队列中选择一个子集S使得(sum_{(w,v)in S}w) mod (pin[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
    ",solve(l,r));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    金额转换问题
    进制转换(十进制->二进制、八进制、十六进制)
    Linux下Tomcat的安装
    Linux下安装jdk配置java环境变量
    Linux下安装Mysql
    在Linux下安装Redis
    Redis常用操作
    阿里云服务器部署tomcat服务器无法访问
    mysql 创建数据库 编码
    docker 安装oracle
  • 原文地址:https://www.cnblogs.com/zmyzmy/p/13709316.html
Copyright © 2011-2022 走看看