Live2D

题解 贪玩蓝月

题目传送门

题目大意

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

设操作次数为\(m\),则保证 \(m\le 5\times 10^4,p\le 500\)

思路

线段树分治

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

暴力重构

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

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

\(\texttt{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 ('\n');
	}
	return 0;
}
posted @ 2020-08-07 15:45  Dark_Romance  阅读(151)  评论(0编辑  收藏  举报