• LOJ 6515 「雅礼集训 2018 Day10」贪玩蓝月


    \(\text{Description}\)

    传送门

    \(\text{Solution}\)

    你会发现题目就是让你维护一个 "可撤销" 的 \(01\) 背包。不过背包应该是不能撤销的。也有可能是我太鶸了

    我们可以根本不撤销 —— 线段树分治。只需要算出每件装备的存在区间,插入线段树上即可。每件装备只用插入 \(\mathcal O(\log m)\) 次,单次查询是 \(\mathcal O(p)\) 的。总共是 \(\mathcal O(pm\log m)\) 的。听上去好像挺卡的

    或者,选用一个撤销代价不那么大的做法。

    考虑用两个栈维护两端的插入。

    插入时将新装备加入对应栈的背包。删除就直接删。如果一个栈删完了就需要将另一个栈内元素分成两半,再重新插入和计算背包。

    单次查询可以用 \(\rm st\) 表将两个栈拼起来,是 \(\mathcal O(p\log p)\) 的。重要的是分析删除的复杂度:如果用 \(\mathcal O(xp)\) 的时间复杂度将 \(x\) 个元素重新插入两个栈里,那么至少再删除 \(x/2\) 次才能够激发新的重构,我们将这两个操作捆绑在一起考虑,所以重构复杂度是 \(\mathcal O(mp)\) 级别的。

    \(\text{Code}\)

    #include <cstdio>
    
    #define rep(i,_l,_r) for(register signed i=(_l),_end=(_r);i<=_end;++i)
    #define fep(i,_l,_r) for(register signed i=(_l),_end=(_r);i>=_end;--i)
    #define print(x,y) write(x),putchar(y)
    
    template <class T> inline T read(const T sample) {
        T x=0; int f=1; char s;
        while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
        while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
        return x*f;
    }
    template <class T> inline void write(const T x) {
        if(x<0) return (void) (putchar('-'),write(-x));
        if(x>9) write(x/10);
        putchar(x%10^48);
    }
    
    #include <cstring>
    #include <iostream>
    using namespace std;
    
    typedef long long ll;
    
    const int maxm=5e4+5,maxp=505;
    
    int m,mod,tp[2],a,b,lg[maxp];
    char op[5];
    ll f[2][maxm][maxp],st[maxp][11],ans;
    struct node {
    	int w,v;
    } sta[2][maxm];
    
    ll Ask(int l,int r) {
    	int len=lg[r-l+1];
    	return max(st[l][len],st[r-(1<<len)+1][len]);
    }
    
    void Query() {
    	int l,r;
    	a=read(9),b=read(9); ans=-1;
    	rep(i,0,mod-1) st[i][0]=f[1][tp[1]][i];
    	rep(j,1,9) for(int i=0;i+(1<<j)-1<mod;++i) st[i][j]=max(st[i][j-1],st[i+(1<<j-1)][j-1]);
    	rep(i,0,mod-1) 
    		if(f[0][tp[0]][i]>=0) {
    			l=a-i,r=b-i;
    			if(l<0) l+=mod;
    			if(r<0) r+=mod;
    			if(l<=r) ans=max(ans,f[0][tp[0]][i]+Ask(l,r));
    			else ans=max(ans,f[0][tp[0]][i]+max(Ask(l,mod-1),Ask(0,r)));
    		}
    	print(ans,'\n');
    }
    
    void Insert(bool x,int a,int b) {
    	sta[x][++tp[x]]=(node){a,b};
    	int j;
    	rep(i,0,mod-1) {
    		j=(i+a>=mod?i+a-mod:i+a);
    		f[x][tp[x]][j]=max(f[x][tp[x]-1][j],f[x][tp[x]-1][i]+b);
    	}
    }
    
    void Delete(bool x) {
    	if(tp[x]) return (void)(--tp[x]);
    	int mid=tp[x^1]+1>>1;
    	// 此处 mid 取大于等于 1/2,是为了保证至少拿出一件物品
    	fep(i,mid,2) Insert(x,sta[x^1][i].w,sta[x^1][i].v);
    	int tmp=tp[x^1]; tp[x^1]=0;
    	rep(i,mid+1,tmp) Insert(x^1,sta[x^1][i].w,sta[x^1][i].v);
    }
    
    int main() {
    	read(9),m=read(9),mod=read(9); 
    	memset(f,192,sizeof f);
    	f[0][0][0]=f[1][0][0]=0;
    	rep(i,2,mod) lg[i]=lg[i>>1]+1;
    	while(m--) {
    		scanf("%s",op);
    		if(op[0]=='I') a=read(9)%mod,b=read(9),Insert(op[1]=='G',a,b);
    		else if(op[0]=='D') Delete(op[1]=='G');
    		else Query();
    	}
    	return 0;
    }
    

    \(\text{I love Wordle!!!}\)

    见缝插针

    I guessed this 5-letter word in 3/6 tries.

    ⬛⬛⬛
    ⬛⬛

    Can you guess this word?

  • 相关阅读:
    matlab练习程序(连续系统辨识与响应)
    【转】灵敏度可以是负值吗_【技术指南】 精确度,准确度,分辨率和灵敏度
    XStream升级1.4.18问题 规格严格
    基于Flink的网络流量实时解析 规格严格
    Maven构建时报错,File encoding has not been set, using platform encoding GBK解决方法 规格严格
    Spring Boot动态修改日志级别 规格严格
    内存分析工具 规格严格
    ES5.6.12客户端连接报错Caused by: java.lang.ClassNotFoundException: org.elasticsearch.http.AbstractHttpServe 规格严格
    动态调整日志等级 规格严格
    时序数据库存储初识1 规格严格
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/14075228.html
Copyright © 2020-2023  润新知