🎬 博主名称 :个人主页
⛺️心简单,世界就简单
序言
最近有些摆,emmmm然后水的文章只有最近学校让写的这些练习了,其实这些之前的文章也讲过模板,也确实该练习一下

目录
字符串哈希
思路:
题目说让你求得给出的这几个字符串有几个不同的字符串,那我们就可以求出每个字符串的哈希值,然后扔给set,然后直接输出set的size就行
我们求哈希值的过程再来说一下吧
1,**这一步这道题不需要,**先与处理一下,P的几次方,然后我们看一下字符串大小,大约是1000,那我们预处理到1005得到P的1005的大小就行,P取131,然后以前还说要mod 2^64,我们把数据类型给缓存unsigned int就行,这样溢出就相当于mod了
2,计算前i个数的哈希值,也就是每个位置的哈希前缀,这里我用了二维数组存取,也就是h[i][j]意思就是第 i 个字符串的前 j 个字符的哈希前缀,我们字符串的第一位就是换算到二进制算法里的那个乘2的最高位的数,所以每次计算时候h[j - 1] * P
for(int j = 1; j <= sizes; j++){
h[i][j] = h[i][j - 1] * P + str[j];
}
3,这道题很简单了,没有让你计算一个字符串里某个区间的哈希值,那个还要再麻烦一点点
cpp
#include<iostream>
#include<string>
#include<string.h>
#include<set>
using namespace std;
typedef unsigned long long ULL;
const int N =1e4 + 10, P = 131;
int n, m;
char str[N];
ULL h[N][1550], p[N];
int t[N];
//用不着
//ULL get(int l, int r){
// return h[r] - h[l - 1] * p[r - l + 1];
//}
void f(){
}
int main(){
scanf("%d", &n);
p[0] = 1;
//用不着
for(int i = 1; i <= 1005; i ++){
p[i] = p[i - 1] * P;
}
for(int i = 1; i <= n; i++){
scanf("%s", str + 1);
int sizes = strlen(str + 1);
// cout<<sizes<<'*';
for(int j = 1; j <= sizes; j++){
h[i][j] = h[i][j - 1] * P + str[j];
}
t[i] = h[i][sizes];
}
set<int> st;
for(int i = 1; i <= n; i++){
st.insert(t[i]);
}
cout << st.size();
}
KMP
思路:这个就是让你计算s2出现在s1所有位置的第一个字符的位置,最后再输出一遍next数组就行
cpp
#include<iostream>
#include<string.h>
using namespace std;
const int N = 1e6 + 10;
const int M = 1e6 +10;
char S[M], P[N];
int ne[N];
int n, m;
int main(){
cin >>(S + 1);
cin >> (P + 1) ;
n = strlen( P + 1);
m = strlen( S + 1);
//求next过程
for(int i = 2, j = 0; i <= n;i ++){
while(j && P[i] != P[j + 1]) j = ne[j];
if(P[i] == P[j + 1]) j ++;
ne[i] = j;
}
for(int i = 1, j = 0;i <=m; i++ ){
while(j && S[i] != P[j + 1]) j = ne[j];
if(S[i] == P[j + 1]) j ++;
if(j == n){
//匹配成功
printf("%d\n", i - n + 1);//题目字符串从1开始的所以再加个1
j = ne[j];//成功后可能后面还有能匹配的,继续操作
}
}
for(int i = 1; i <= n; i ++) cout << ne[i] <<' ';
cout<< '\n';
}
字典树
思路:这个就是trie树哈,这个就根我之前那个模板题差不多
我再来说说怎么建树,就是想象出来一颗树,然后这个题是字符串含有的是数字和字母,然后我们用数组来存树son[ p ][ u ],p是某个节点,u是这个节点伸出来的字符,然后这个数组就是一个节点idx编号,当我们想向下继续延申,就让p等于这个idx就行,然后继续延申
然后我们之前文章里的模板是只能查出一个字符串是否出现过,这个是查出一个字符串是否在之前的字符串的前缀里,我们的cnt数组就要用来记录节点的出现次数了
cpp
#include<iostream>
#include<cstring>
#include<string.h>
using namespace std;
const int N = 3e6 + 10;
char str[N];
int son[N][65], cnt[N], idx;//下标是0的带你,既是根节点又是 空节点
//cnt是以当前这个点结尾的单词有多少个
//插入操作
int getnum(char x){
if(x>='A'&&x<='Z')
return x-'A';
else if(x>='a'&&x<='z')
return x-'a'+26;
else
return x-'0'+52;
}
void insert(char str[]){
int p = 0;//从根节点开始,从0开始遍历
for(int i = 0; str[i]; i ++){
int u =getnum(str[i]);
//如果p这个节点不存在u这个儿子,就创建一个
if(!son[p][u]) son[p][u] = ++idx;
p = son[p][u];
cnt[p]++;
}
}
//查询操作
int query(char str[]){
int p = 0;
int u;
for(int i = 0; str[i]; i ++){
u = getnum(str[i]);
if(!son[p][u]) return 0;
p = son[p][u];
}
return cnt[p];
}
int main(){
int t;
scanf("%d", &t);
while(t --){
for(int i = 0;i <= idx; i++ ){
cnt[i] = 0;
for(int j = 0; j<65; j++)
son[i][j] = 0;
}
idx = 0;
int n, m;
scanf("%d%d", &n, &m);
while(n --){
scanf("%s", str);
insert(str);
}
while(m --){
scanf("%s", str);
printf("%d\n", query(str)) ;
}
}
}
最长异或和路径
思路:这个其实很麻烦的我感觉,就是之前我做的模板计算给一堆数,让找到哪数异或和最大
但是这个还给了路径,但其实仔细观摩后,我们可以发现其实是一回事的,我们先记录所有的异或路径的异或值,然后存起来,然后我们又知道,两个路径相互异或后,相同的那段路径就抵消了,所以我们就可以得到了
1,我们先利用dfs求出所有节点到自己根节点的异或路径值
2,然后就开始正常的insert和query,我们建树是让每个值的二进制给仍在树里
cpp
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
const int N = 1e5 + 10, M = 3300000;
int n;
int son[M][2], idx, sum[N];
int a[N];
int h[N * 2], ne[N * 2], w[N * 2], e[N * 2], id;
void add(int a, int b, int c){
e[id] = b;
w[id] = c;
ne[id] = h[a];
h[a] = id ++;
}
void dfs(int u, int fa){
for(int i = h[u]; i != -1; i = ne[i]){
int t = e[i];
int wei = w[i];
if(t != fa){
sum[t] = wei ^ sum[u];
dfs(t, u);
}
}
}
void insert(int x){
int p = 0;
for(int i = 31; ~i; i --){
int &s = son[p][x >> i & 1];
if(!s) s = ++ idx;
p = s;
}
}
int query(int x){
int res = 0, p = 0;
for(int i = 31; ~i; i --){
int s = x >> i & 1;
if(son[p][!s]){
res += 1 << i;
p = son[p][!s];
}
else{
res += 0 << i;//可以省略
p = son[p][s];
}
}
return res;
}
int main(){
memset(h, -1, sizeof h);
cin >> n;
for(int i = 1; i < n; i ++){
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
add(u, v, w);
add(v, u, w);
}
dfs(1, -1);
int res = 0;
for(int i = 1; i <= n; i ++){
insert(sum[i]);
}
for(int i = 1; i <= n; i ++){
res = max(res, query(sum[i]));
}
cout << res;
}
码字不易,给个三连吧,谢谢谢谢大家




