zoukankan      html  css  js  c++  java
  • 题解 贪玩蓝月

    题目传送门

    题目大意

    给出一种元素 ((u,w)) ,表示它的特征值为 (u) ,战斗力为 (w) 。现在给你一个双端队列,维护该元素,支持两端加点删点,以及查询特征值之和(pmod p)([l,r]) 之内的战斗力之和最大的子序列。

    设操作次数为(m),则保证 (mle 5 imes 10^4,ple 500)

    思路

    线段树分治

    因为懒(菜)得(不)一(可)批(言),所以我并没有对其进行实现,所以下面的纯属口胡。不难看出每个元素出现是有时间的,所以我们就可以使用线段树分治,直接dp即可。时间复杂度 (Theta(mplog m)),但是实际上有一个 (dfrac{5}{7}) 的常数,应该不会很慢。

    暴力重构

    我们发现,我们其实可以用两个栈来维护这个双端队列,一个维护一边,从中间断开。然后如果一个栈删没了就直接暴力重构把拆分点设为另一个的中间。于是问题就是如何合并两个栈里面的答案,其实我们发现如果我们确定在一个栈里面我们特征值的多少,那么,余数的范围我们也固定了,于是,我们就可以区间查询(max)即可,这个可以用单调队列、st表、线段树做。

    时间复杂度加点删点均摊是 (Theta(p)) (维护dp值),合并如果是单调队列就是 (Theta(p)) ,另外两种就是 (Theta(plog p)),总时间复杂度就是 (Theta(mp)/Theta(mplog p)) 的。

    ( exttt{Code})

    #include <bits/stdc++.h>
    using namespace std;
    
    #define PII pair<int,int>
    #define Int register int
    #define MAXN 50005
    #define MAXM 505
    
    PII t[2][MAXN];//储存的是 
    int mod,inf,top[2],f[2][MAXN][MAXM],st[MAXN][20];
    
    template <typename T>inline void chkmax (T &a,T b){a = a > b ? a : b;}
    
    void ins (bool k,int now,PII p){
    	t[k][now] = p;
    	for (Int i = 0;i < mod;++ i) f[k][now][i] = f[k][now - 1][i];
    	for (Int i = 0;i < mod;++ i) chkmax (f[k][now][(i + p.first) % mod],f[k][now - 1][i] + p.second);
    }
    
    void del (bool k){
    	if (top[k]) return -- top[k],void ();
    	int mid = (1 + top[k ^ 1]) >> 1;
    	for (Int i = 1;i <= mid;++ i) t[k][mid - i + 1] = t[k ^ 1][i],t[k ^ 1][i] = t[k ^ 1][i + mid];
    	top[k] = mid - 1,top[k ^ 1] = top[k ^ 1] & 1 ? mid - 1 : mid;
    	for (Int i = 1;i <= top[k];++ i) ins (k,i,t[k][i]);
    	for (Int i = 1;i <= top[k ^ 1];++ i) ins (k ^ 1,i,t[k ^ 1][i]);
    }
    
    int querymax (int l,int r){
    	int k = log2 (r - l + 1);
    	return max (st[l][k],st[r - (1 << k) + 1][k]);
    }
    
    int query (int l,int r){
    	int ans = -inf;
    	for (Int i = 0;i < mod;++ i) st[i][0] = f[0][top[0]][i];
    	for (Int j = 1;(1 << j) <= mod;++ j)
    		for (Int i = 0;i + (1 << j) <= mod;++ i)
    			st[i][j] = max (st[i][j - 1],st[i + (1 << j - 1)][j - 1]);
    	for (Int i = 0;i < mod;++ i){
    		if (f[1][top[1]][i] < 0) continue;
    		int L = l - i,R = r - i;
    		L = (L + mod) % mod,R = (R + mod) % mod;
    		if (L <= R) chkmax (ans,f[1][top[1]][i] + querymax (L,R));
    		else chkmax (ans,f[1][top[1]][i] + max (querymax (L,mod - 1),querymax (0,R)));
    	}
    	return ans < 0 ? -1 : ans;
    }
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    
    signed main(){
    	int t,n;read (t,n,mod);
    	memset (f,0xcf,sizeof (f)),inf = -f[0][0][0],f[0][0][0] = f[1][0][0] = 0;
    	char s[22] = {};while (n --> 0){
    		int x,y;scanf ("%s",s);
    		if (s[0] == 'I') read (x,y),ins (s[1] == 'G',++ top[s[1] == 'G'],make_pair (x % mod,y));
    		else if (s[0] == 'D') del (s[1] == 'G');
    		else read (x,y),write (query (x,y)),putchar ('
    ');
    	}
    	return 0;
    }
    
  • 相关阅读:
    MRO C3算法 super的运用
    约束 抛异常
    反射
    Ubuntu
    Vim
    Vim
    Arithmetic
    Docker-常用命令
    Docker
    Docker-LAMP开发环境
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/13453298.html
Copyright © 2011-2022 走看看