1. 程式人生 > 實用技巧 >【題解】【bzoj1819】【JSOI】Word Query電子字典

【題解】【bzoj1819】【JSOI】Word Query電子字典

屑人屑題解。

做完去題解區翻了一波,全是沒想到的Trie+連結串列。

表示只會字串hash /kel。

懶得寫格式了。

首先,維護兩個umap(其實是代替umset的),一個是單詞表,一個是變化過的單詞表。

變化過的單詞表分兩種:原單詞刪去一個字母和原單詞把一個字母改成 $

查詢的時候先看單詞表裡有沒有,沒有的話,先直接在變化表裡查一個,再選一個字母刪掉再查一個,再把一個字母改成 $ 再查一個。

注意,為了防止出現一些奇奇怪怪的重複,插入和查詢時需要一個uset來去重

為什麼不直接用umap存字串而還要先hash再存?空間問題~

上程式碼吧

#include<bits/stdc++.h>
#pragma GCC optimize("Ofast",3,"inline")
using namespace std;
typedef pair<unsigned long long,unsigned long long>ul;//雙雜湊,穩
struct hasher{
	size_t operator()(const ul p)const{
		return (hash<unsigned long long>()(p.first)*13148274ull+hash<unsigned long long>()(p.second))%86850899ull;
	}
};
unordered_map<ul,int,hasher>umap,dict;
ul strhash(string x){
	unsigned long long ret1=0,ret2=0;
	for(auto i:x)ret1=(ret1*INT_MAX+i)%23333333;
	for(auto i:x)ret2=ret2*998244353ull+i;
	return make_pair(ret1,ret2);
}
void insert(string x){
	++dict[strhash(x)];
	unordered_set<ul,hasher>uset;
	for(unsigned i=0;i<x.length();++i){
		auto p(x);
		p[i]='$';
		++umap[strhash(p)];
	}
	for(unsigned i=0;i<x.length();++i){
		auto p(x);
		p.erase(p.begin()+i);
		uset.insert(strhash(p));
	}
	for(auto w:uset)++umap[w];
}
int query(string x){
	const ul w=strhash(x);
	if(dict[w])return -1;
	unordered_set<ul,hasher>uset;
	int ans=umap[w];
	for(unsigned i=0;i<x.length();++i){
		auto p(x);
		p.erase(p.begin()+i);
		uset.insert(strhash(p));
	}
	for(unsigned i=0;i<x.length();++i){
		auto p(x);
		p[i]='$';
		ans+=umap[strhash(p)];
	}
	for(auto l:uset)ans+=dict[l];
	return ans;
}
int main(){
	int n,m;cin>>n>>m;
	for(int i=1;i<=n;++i){
		string x;cin>>x;
		insert(x);
	}
	for(int i=1;i<=m;++i){
		string x;cin>>x;
		cout<<query(x)<<endl;
	}
	return 0;
}