Loading

[THUSC2016] 补退选

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

构建两个哈希表,均为哈希值映射至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;
}

有问题可以私信轰炸我捏

posted @ 2024-03-09 14:04  TongKa  阅读(6)  评论(0编辑  收藏  举报