pbds
也叫做平板电视 Here,内含比 map
快很多的哈希表,甚至平衡树?!
封装了 hash、tree、trie、priority_queue 这四种数据结构
需要万能拓展库头文件 #include<bits/extc++.h>
以及 using namespace __gnu_pbds;
内带哈希表:如:gp_hash_table<int, int>
、cc_hash_table<int, int>
字符串算法
manacher
马拉车算法( ,OI-Wiki
算法介绍: 线性复杂度内找出以每个字符为回文中心的最长回文半径
存下模板代码(只用于求奇数回文):
int l = 0, r = -1;
for(int i=1; i<=n; i++){int k = i > r ? 1 : min(d[l+r-i], r-i+1);while(i - k > 0 and k + i <= n and s[i-k] == s[i+k]) k++;d[i] = k--;if(r < i + k) l = i - k , r = i + k;
}
偶数回文:直接把原字符串每相邻两个字符之间加上一个特殊字符就避免了偶数回文的情况,如 #
当时自己推的板子是个什么构思??
板子题: 【模板】manacher
code
#include<bits/stdc++.h>
#define Aqrfre(x, y) freopen(#x ".in", "r", stdin),freopen(#y ".out", "w", stdout)
#define mp make_pair
#define Type ll
#define qr(x) x=read()
typedef __int128 INT;
typedef long long ll;
using namespace std;inline ll read(){char c=getchar(); ll x=0, f=1;while(!isdigit(c)) (c=='-'?f=-1:f=1), c=getchar();while(isdigit(c)) x=(x<<1)+(x<<3)+(c^48), c=getchar();return x*f;
}const int N = 2.2e7 + 10; int n, d[N];
char in[N], s[N];signed main(){ // a// Aqrfre(a, a);cin>>(in+1); n = strlen(in+1);int cnt = 0;for(int i=1; i<=n; i++)s[++cnt] = '@', s[++cnt] = in[i];s[++cnt] = '@'; n = cnt;int l = 0, r = -1, ans = 0;for(int i=1; i<=n; i++){int k = i > r ? 1 : min(d[l+r-i], r-i+1);while(i - k > 0 and k + i <= n and s[i-k] == s[i+k]) k++;d[i] = k--;if(r < i + k) l = i - k , r = i + k;}for(int i=1; i<=n; i++){if(s[i] == '@') ans = max(ans, d[i] / 2 * 2); else ans = max(ans, d[i] - !(d[i] & 1));}cout<<ans<<"\n";return 0;
}
题
最小表示法
用于解决:有一个字符串,这个字符串的首尾是连在一起的,要求寻找一个位置,以该位置为起点的字符串的字典序在所有的字符串中中最小。
CSDN OI-Wiki
解释一下为什么 k==n
的时候 break
,发现这种情况整个字符串是会存在循环节的,并且以循环节的每一个字符为开头都做过一遍了
模板代码:
int k = 0, i = 1, j = 2;
while(i <= n and j <= n){for(k=0; k<n; k++)if(in[i+k] != in[j+k]) break;if(k == n) break;if(in[i+k] < in[j+k]) j = max(j+k+1, i+1); //此时从 i~i+k 为开始的字符串都会小于相应的 j~j+k 位置开始的字符串,所以一定不以 j~j+k 为起点else i = max(i+k+1, j+1);
}i = min(i, j);
题:
Strange string
KMP
利用后缀函数线性求一个模板串在一个文本串里出现的次数或位置等等
CSDN
预处理出模板串的最大相等前后缀,与文本串进行匹配的时候每次匹配不上就将模板串的调到与此时后缀相同的前缀位置
预处理代码
inline void prefix(string s, int pi[]){ // pi[i]表示 s 到第 i 个字符时的串的前后缀的长度int len = s.length();for(int i=1; i<len; i++){int j = pi[i-1]; // j 表示到 i 前一个字符时的前缀最后一个字符的位置 + 1while(j and s[i] != s[j]) j = pi[j-1]; //j 继续往前跳到前缀最后一个字符 + 1 的位置if(s[i] == s[j]) ++j; //找到最大的 j 前后缀匹配上了,长度为位置 + 1pi[i] = j;}
}
模板题
code
#include<bits/stdc++.h>
#define Aqrfre(x, y) freopen(#x ".in", "r", stdin),freopen(#y ".out", "w", stdout)
#define mp make_pair
#define Type int
#define qr(x) x=read()
typedef long long ll;
using namespace std;inline Type read(){char c=getchar(); Type x=0, f=1;while(!isdigit(c)) (c=='-'?f=-1:f=1), c=getchar();while(isdigit(c)) x=(x<<1)+(x<<3)+(c^48), c=getchar();return x*f;
}const int N = 1e6 + 5; string s, t;
int n, m, pre[N];inline void prefix(string s, int pi[]){ int len = s.length();for(int i=1; i<len; i++){int j = pi[i-1]; while(j and s[i] != s[j]) j = pi[j-1]; if(s[i] == s[j]) ++j;pi[i] = j;}
} signed main(){ // a// Aqrfre(a, a);cin>>s>>t;n = s.length(), m = t.length();prefix(t, pre);for(int i=0,j=0; i<n; i++){while(j > 0 and s[i] != t[j]) j = pre[j-1];if(s[i] == t[j]) ++j;if(j == m){cout<<i-m+2<<"\n";j = pre[j-1];}}for(int i=0; i<m; i++) cout<<pre[i]<<" ";return 0;
}