今天复习字符巛 还剩下一点时间 我先 打一下模板
$ 1$ 最小表示法
贪心 首先把 $ S $ 复制一遍成一个环
然后定义两个指针 i j 从 i j 开始一次扩展 字符巛 的长度 即 从$0$ 的长度开始扩展到 $n-1$ ($k $最大到 $n$ >- 停止循环 找到答案)
然后比较其中是否相等
如果不相等就跳过循环
判断 当前 $S[i+k]$ 与$S[j+k]$ 的 大小 因为中间的字符串 都相等 所以 指针可以跳到 $x+k+1$ 处 $[x|i,j]$
然后因为 最小的指针一定不会移动到最大的指针的后面所以 答案为 $min(i,j)$
$ i,j $只循环到 n 的位置 因为以后都是一样的 了
code;
int i=1,j=2; int k=0; while(i<=n&&j<=n) { for(int k=0;k<n;k++) { if(S[i+k]!=S[j+k]) break; } if(k==n) break; if(s[i+k]>s[j+k]) i=i+k+1; else { if(s[i+k]<s[j+k]) j=j+k+1; } if(i==j) j++; } cout<<min(i,j);
2 .01 字典树
作用 : 寻找异或最大值
方法 :
插入: 每位每位地找 没有就扩展 扩展完之后 就插入
code:
void inset(int v) { int u=0; for(int i=32;i>=0;i--) { int k=(sum[v]>>i)&1; if(!ch[u][k]) { ch[u][k]=tot++; } u=ch[u][k]; } val[u]=sum[v]; }
寻找:从最高位 开始 搜寻 先找 不同的 后找相同的 注意 先插入 $sum[0]$ 保证有解
如果 找不到 就一定没有
code:
int find(int v) { int u=0; for(int i=32;i>=0;i--) { int k=(v>>i)&1; if(ch[u][k^1]) u=ch[u][k^1]; else u=ch[u][k]; } return val[u]; }
$3$ 状态很差,但是还是坚持来写下博客啦
KMP
作用 匹配或者最长字串
首先 fail数组 记的是 前i位 的最长前缀和后缀
求fail 数组首先得与自己比对 注意得从第二位开始 求出回退值
code:
fail[0]=-1; int j=-1; for(int i=1;i<s[1].size();i++) { while(j>-1&&(s[1][j+1]!=s[1][i])) j=fail[j]; if(s[1][j+1]==s[1][i]) j++; fail[i]=j; }
求匹配 匹配使得前后缀一样 就很强 从第一位开始
int j=-1; int ans=0; fail[0]=-1; for(int i=0;i<s[v].size();i++) { while(j>-1&&(s[1][j+1]!=s[v][i])) { ans=max(ans,j); j=fail[j];} if(s[1][j+1]==s[v][i]) j++; if(j==m)
{
ans=max(j+1,ans);
}
} return ans;
$@$求最长公共字串匹配
找一个串 然后挨个匹配 找最小值 然后删除第一个元素 再次找最小值 最后取max
介绍一下动态数组的erase神操作
#include<bits/stdc++.h> using namespace std; int n; string s[8]; int fail[3000]; int kmp(int v) { int j=-1; int ans=0; fail[0]=-1; for(int i=0;i<s[v].size();i++) { while(j>-1&&(s[1][j+1]!=s[v][i])) { ans=max(ans,j); j=fail[j];} if(s[1][j+1]==s[v][i]) j++; ans=max(ans,j+1); } return ans; } int main() { cin>>n; for(int i=1;i<=n;i++) { cin>>s[i]; } int aans=0; while(s[1].size()) { int ans=100000000; fail[0]=-1; int j=-1; for(int i=1;i<s[1].size();i++) { while(j>-1&&(s[1][j+1]!=s[1][i])) j=fail[j]; if(s[1][j+1]==s[1][i]) j++; fail[i]=j; } for(int i=2;i<=n;i++) { ans=min(ans,kmp(i)); } aans=max(aans,ans); s[1].erase(s[1].begin()); } cout<<aans; }
$@@$结论 字符串乘方 i%(i-fail[i])==0 那么一定有乘方 个数为$i/(i-fail[i])$
$4$马拉车
首先初始化 把回文串都变成奇数回文串
类似于这样
void init() { S[0]='#'; S[1]='#'; for(int i=0;i<strlen(s);i++) { S[++tot]=s[i]; S[++tot]='#'; } S[++tot]='