首页 > 其他分享 >[THUSC2016] 补退选

[THUSC2016] 补退选

时间:2024-03-09 14:11:54浏览次数:28  
标签:v1 int 退选 THUSC2016 v2 vector mp2 哈希

首先对于所有的字符串进行哈希

构建两个哈希表,均为哈希值映射至vector

我们约定一些东西方便表示

\(v1\) 表示第一个哈希表对应的vector, \(v2\) 表示第二个哈希表对应的vector

\(v1\) 中元素表示当前该前缀对应所有操作编号(可能不正确,但是没影响,具体看下面的 注意 标注的地方)

第二个哈希表的vector(即 \(v2\) )表示所有历史出现过的情况(即这个vector只加不减)。如果 \(v1.size()\) 超过 \(v2.size()\) ,那么向 \(v2\) 尾部加入 \(v1\) 中元素

那么 \(mp2[x]\) 这个 \(v2\) 的 \(v2[y]\) 表示,编号为 \(v2[y]\) 的操作结束后,哈希值为 \(x\) 的前缀个数为 \(y\)

对于 \(opt1\) ,把 \(s\) 的每一个前缀对应的哈希值丢进map里面,在对应vector最后插入这个操作的编号,复杂度 \(O(|s|)\)

对于 \(opt2\) ,把 \(s\) 的每一个前缀对应的 \(v1\) 的最后一个元素删去。 \(O(|s|)\) 。

对于 \(opt3\) ,询问为 \(v\) ,把 \(s\) 整个串的哈希值对应 \(v2\),直接询问 \(v2[v+1]\) 对应编号。这一步是 \(O(|s|)\) 的,因为要处理出哈希值。

注意:这样维护 \(opt2\) 并不能保证删去了正确的元素。

比如,我先插入一个 \(aaabzzz\) ,而后又插入了一个 \(aaabyyy\) ,再删除了 \(aaabzzz\) 。设 \(hash("aaab")=x\) 。直接删除最后一个,对 \(mp1[x]\) 删去的是插入 \(aaabyyy\) 的操作编号。

设插入 \(aaabyyy\) 后,前缀 \(aaab\) 的答案为 \(v_0\)

但是由于在对 \(aaabyyy\) 插入时,我把 \(v1\) 尾部元素插入了 \(v2\),而我会在 \(v2\) 中查询答案。所以对询问为 \(v_0\) 的贡献,已经正确的记录在了 \(v2\) 中,所以删除了也不影响。

这图没有画出 \(v1,v2\) 的区别,所以看不懂不用纠结。

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>

typedef unsigned long long ull;

const ull BB = 13;
const int N = 66;

using namespace std;
using namespace __gnu_pbds;//pbds跑的快一些

int q , Q;

char s[N]; int len;
ull h[N] , B[N];
void gethash(){
	for(int i = 1; i <= len; ++ i){
		h[i] = h[i - 1] * BB + s[i];
	}
}

gp_hash_table<ull , vector<int> > mp1 , mp2;//1为当前,2为历史
long long lstans = 0;
void solve(){
	int op; cin >> op;
	cin >> (s + 1);
	len = strlen(s + 1);
	gethash();
	if(op == 1){
		for(int i = 1; i <= len; ++ i){
			mp1[h[i]].push_back(Q);
			if(mp1[h[i]].size() > mp2[h[i]].size()){
				mp2[h[i]].push_back(Q);
			}
		}
	}
	if(op == 2){
		for(int i = 1; i <= len; ++ i){
			mp1[h[i]].pop_back();
		}
	}
	if(op == 3){
		long long a , b , c;//注意1e5*1e5>INT_MAX
		cin >> a >> b >> c;
		int v = (a * llabs(lstans) + b) % c;
		if(mp2.find(h[len]) == mp2.end()){
			cout << -1 << endl;
			lstans = -1;
		}
		else if(mp2[h[len]].size() <= v){
			cout << -1 << endl;
			lstans = -1;
		}
		else {
			cout << mp2[h[len]][v] << endl;
			lstans = mp2[h[len]][v];//注意记录lstans,模拟考时我差点没记录,在线改离线qwq
		}
	}
}

int main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	
//	freopen("C.in" , "r" , stdin);
//	freopen("C.out" , "w" , stdout);
	
	B[0] = 1;
	for(int i = 1; i <= 50; ++ i){
		B[i] = B[i - 1] * BB;
	}
	cin >> q;
	for(Q = 1; Q <= q; ++ Q) solve();
	
	return 0;
}

有问题可以私信轰炸我捏

标签:v1,int,退选,THUSC2016,v2,vector,mp2,哈希
From: https://www.cnblogs.com/TongKa/p/18062643

相关文章

  • P5336 [THUSC2016] 成绩单
    这得是区间dp。还需要限制一下值域。因此dp状态时\(f_{l,r,x,y}\)表示使\([l,r]\)区间所有值都处于\([x,y]\)的最小花费。设\(g_{l,r}=\min\{f_{l,r,x,y}+a+b(x-y)^2\}\)。思考一个序列可以被怎么消掉。维护一个类似括号序列的东西,左右匹配的括号......
  • P5336 [THUSC2016]成绩单
    题意:期末考试结束了,班主任L老师要将成绩单分发到每位同学手中。L老师共有\(n\)份成绩单,按照编号从\(1\)到\(n\)的顺序叠放在桌子上,其中编号为\(i\)的的成绩单分数为\(W_i\)。成绩单是按照批次发放的。发放成绩单时,L老师会从当前的一叠成绩单中抽取连续的一段,让这......
  • [THUSC2016]成绩单
    这个题貌似是一类套路题啊,但是我好像没有见过(;′⌒`)。我们首先要观察到一个关键性质:每次操作可以看成原序列上一个区间,且任两个区间要么不交要么包含。我们考虑最外层之间的拼接是简单的,所以不妨只考虑区间\([l,r]\)被同一个最外层区间包含的情况。倘若我们记\(dp_{l,r,v_1......
  • 做题记录整理dp14 P5336 [THUSC2016]成绩单(2022/9/27)
    P5336[THUSC2016]成绩单这题难度标的虚高首先一眼区间dp,然后写出递推方程然后发现爆空间,再上离散化然后就没了。。。撑死也就是蓝题不过学到了一个离散化技巧#incl......