字符串乱搞&Tricks
0.省流版
- 字符集是26个小写字母,Trie的循环里面不要写异或,写减号
map<int,array<bool,(size)> >可能比bitset占空间更小- 求树上两点间边权/点权异或和,直接预处理到根节点的异或和,因为自反性直接
xor起来就行 - 有时候发现总体做法可以用通用毒瘤数据hack,可以试试特判这类数据找局部新做法(仅限骗分
- 双向链表是个\(\large\color{cornflowerblue}嚎\color{goldenrod}动\color{gold}戏\)
1.字符串hash
to be continued...
2.KMP
to be continued...
3.Manacher
to be continued...
4.ExKMP
to be continued...
5.Trie
-
用
map套静态数组卡空间
应用:P3879 阅读理解
这题出出来就是为了卡空间的
一开始用vector<int>存了以每个点为结尾的串所属文章号
然后就\(\tt \color{purple}{MLE}\)了
去搜了下,发现map不仅可以套vector还可以套静态数组array
它的声明是:
array < Typename , Size > Array_Name
然后用它存了bool来判断每篇文章是否有这个串
一开始看错了数据范围,定义了一个10001大小的,发现还是MLE,遂康康TJ换成了bitset<10001> mp[MAXN],结果它直接\(\tt \color{yellow}{CE}\)了???
然后才发现dev本地编译时,map可以过而bitset不能过
然后才发现我范围开错了……
吔,等等
那map怎么过了(
所以就成功地发现了这个东西的nb之处(

上边的是bitset,下边的是map套array
可以发现,这样套出来竟然比bitset这种极致压缩的结构占空间还要小!
虽然不懂原理,而且我觉得这样写的空间其实跟数据有关
但是以后如果bitset写锅了,或者毒瘤人卡了空间
可以试试map套静态数组.
另外,bitset还是比map要快的(
code:
#include <bits/stdc++.h>
#define ri register int
#define MAXN 5000001
#define g() getchar()
#define pc(a) putchar(a)
#define Tp template<typename T>
using namespace std;
namespace SlowIO
{
Tp inline void rd(T &x) {
x=0;char i=g();bool f=1;
while(!isdigit(i)) f&=(i!='-'),i=g();
while(isdigit(i)) x=(x<<3)+(x<<1)+(i^48),i=g();
x*=((f<<1)-1);
}
Tp inline void op(T x){
if(x<0) pc('-'),x=-x;
if(x>=10) op(x/10);
pc(x%10+48);
}
Tp inline void writeln(T x){op(x);pc('\n');}
Tp inline void writesp(T x){op(x);pc(' ');}
Tp inline void writespf(T x){pc(' ');op(x);}
};
using namespace SlowIO;
int trie[MAXN][26];
int n,m,tot;
map<int,array<bool,1001> > mp;
string s;
void insert(int ind){
ri ptr=0,len=s.length();
for(ri i=0;i<len;i++){
ri t=(s[i]-'a'); //千万 不要 打成 ^
if(!trie[ptr][t])
trie[ptr][t]=++tot;
ptr=trie[ptr][t];
} mp[ptr][ind]=1;
}
void getans(){
ri ptr=0,len=s.length();
for(ri i=0;i<len;i++){
ri t=(s[i]-'a');
if(!trie[ptr][t]) return;
ptr=trie[ptr][t];
}
for(ri i=1;i<=n;i++)
if(mp[ptr][i]) writesp(i);
}
int main()
{
rd(n);
for(ri i=1;i<=n;i++){
rd(m);
for(ri j=0;j<m;j++)
cin>>s,insert(i);
} rd(m);
while(m--){
cin>>s;
getans(); pc('\n');
}
return 0;
}
0x3f.Not end
最后放一个字符串全家桶
包括 \(\tt{KMP}\) 、 \(\tt{Manacher}\) 、 \(\tt{ExKMP}\) 、 \(\tt{Trie}\) 、 \(\tt{0/1Trie}\) 、 \(\tt{AC自动机}\) 、 \(\tt{可持久化0/1Trie}\) ,咕了的有 \(\tt{可持久化普通Trie}\) 和 \(\tt{平衡Trie}\) (在这里看到的
#include <bits/stdc++.h>
#define ri register int
#define MAXN 1000001
using namespace std;
inline void Sync(){
ios::sync_with_stdio(false);
cin.tie(NULL),cout.tie(NULL);
}
//String Algorithm & DS Templates
struct Kmp{
int nxt[MAXN],lens,lent;
char s[MAXN],t[MAXN];
inline void pres(){
ri t1=0,t2=nxt[0]=-1;
while(t1<lens)
if(!(~t2)||s[t1]==s[t2])
nxt[++t1]=++t2;
else t2=nxt[t2];
}
inline bool KMP(){
ri t1=0,t2=0;
while(t1<lens&&t2<lent)
if(!(~t2)||s[t1]==t[t2])
++t1,++t2;
else t2=nxt[t2];
return t2==lent;
}
};
struct Manacher{
int Rel[MAXN],ans[MAXN];
int Mxr,ind,lens;
string s;
inline void M1nacher(){
string buf="%#";
for(ri i=0;i<lens;i++)
buf+=s[i],buf+="#";
for(ri i=0,j;i<lens;i++){
j=(ind<<1)-i;
Rel[i]=(i<Mxr?min(Rel[j],Mxr-i):1);
while(s[i+Rel[i]]==s[i-Rel[i]])
++Rel[i];
if(i+Rel[i]>Mxr)
Mxr=i+Rel[i],ind=i;
ans[i]=Rel[i]-1;
}
}
};
struct Trie{
#define C 26
int trie[MAXN][C];
int tag[MAXN],tot;
inline void insert(string s){
ri ptr=0,len=s.length();
for(ri i=0;i<len;i++){
ri t=s[i]-'a';
if(!trie[ptr][t]) trie[ptr][t]=++tot;
ptr=trie[ptr][t];
} tag[ptr]=1;
}
inline bool find(string s){
ri ptr=0,len=s.length();
for(ri i=0;i<len;i++){
ri t=s[i]-'a';
if(!trie[ptr][t]) return 0;
ptr=trie[ptr][t];
} return 1;
}
};
struct AC_Automaton{
#define C 26
int trie[MAXN][C],tot,tag[MAXN],fst[MAXN];
int fail[MAXN],ans[MAXN],indeg[MAXN],res[MAXN];
int q[MAXN],l=1,r;
inline void insert(string s,int ind){
ri ptr=0,len=s.length();
for(ri i=0;i<len;i++){
ri t=s[i]-'a';
if(!trie[ptr][t]) trie[ptr][t]=++tot;
ptr=trie[ptr][t];
} if(!tag[ptr]) tag[ptr]=ind;
fst[ind]=tag[ptr];
}
inline void getfail(){
for(ri i=0;i<C;i++)
if(trie[0][i]) q[++r]=trie[0][i],indeg[0]++;
while(l<=r){
int u=q[l++];
for(ri i=0;i<C;i++)
if(trie[u][i])
fail[trie[u][i]]=trie[fail[u]][i],indeg[fail[trie[u][i]]]++,
q[++r]=trie[u][i];
else trie[u][i]=trie[fail[u]][i];
}
}
inline void topo(){
l=1,r=0;
for(ri i=0;i<=tot;i++)
if(!indeg[i]) q[++r]=i;
while(l<=r){
int u=q[l++];
res[tag[u]]=ans[u];
int v=fail[u];
indeg[v]--,ans[v]+=ans[u];
if(!indeg[v]) q[++r]=v;
}
}
inline void getans(string s){
ri ptr=0,len=s.length();
for(ri i=0;i<len;i++){
ptr=trie[ptr][s[i]-'a'];
ans[ptr]++;
} topo();
}
};
struct ExKmp{
int nxt[MAXN],zf[MAXN];
char a[MAXN],b[MAXN];
int lena,lenb;
inline void pres(){
lenb=strlen(b);
ri i=0,j=0; nxt[0]=lenb;
while(i+1<lenb&&b[i]==b[i+1]) ++i;
nxt[1]=i; ri ind=1,Mxr=i+1;
for(i=2;i<lenb;i++){
if(i+nxt[i-ind]<Mxr)
nxt[i]=nxt[i-ind];
else{
j=max(Mxr-i,0);
while(i+j<lenb&&b[j]==b[i+j]) ++j;
nxt[i]=j,Mxr=i+nxt[i],ind=i;
}
}
}
inline void ExKMP(){
lena=strlen(a);
ri i=0,j=0,ind=0,Mxr=0;
for(;i<lena;i++){
if(i+nxt[i-ind]<Mxr)
zf[i]=nxt[i-ind];
else{
j=max(Mxr-i,0);
while(i+j<lena&&j<lenb&&a[i+j]==b[j]) ++j;
zf[i]=j,ind=i,Mxr=i+zf[i];
}
}
}
}exkmp;
struct BitTrie{
#define TRIE MAXN*31 //此题最高只到2^31 for this problem only up to 2^31
/*
这里提醒一点:
算术移位的范围不能超过变量本身表示的范围.
所以如果上界取到了32,请开long long (
*/
int trie[TRIE][2]; //0/1Trie的主体 the main of BitTrie
bool flag[TRIE]; //给某个数的尾节点打上标记 to flag a node that it's the end of a certain number x (in this problem it's useless)
int tot; //节点总数 total number of nodes
inline void Insert(int x){
ri ptr=0;
for(ri i=31;i>=0;i--){
ri t=(x>>i)&1;
if(!trie[ptr][t])
trie[ptr][t]=++tot;
ptr=trie[ptr][t];
} flag[ptr]=1;
} //向0/1Trie中插入一个数x insert number x into BitTrie
inline int QueMax(int x){
ri ptr=0,xsum=0; //直接在贪心选择时计算异或和 directly calculate the xsum with bits on the path
for(ri i=31;i>=0;i--){
ri t=(x>>i)&1;
if(trie[ptr][t^1]){
xsum|=(1<<i); //只有当两数该位可以相反时,这一位才计入答案 only when they differ , this bit could be added into the XOR_SUM
ptr=trie[ptr][t^1];
} else ptr=trie[ptr][t];
} return xsum;
} //查询0/1Trie中的数与x的最大异或和 query the Max XOR_SUM with number x in BitTrie
};
struct Persistable_Trie{
//咕 不想打
};
struct Persistable_BitTrie{
int trie[MAXN<<5][2],tot;
int root[MAXN<<1];
int apr[MAXN<<5]; //节点在所有历史版本中被经过了多少次
inline void Insert(int x,int y,int pre){
root[y]=++tot; ri now=root[y]; pre=root[pre];
for(ri i=24;i>=0;i--){
ri t=(x>>i)&1;
apr[now]=apr[pre]+1;
trie[now][t]=++tot;
trie[now][t^1]=trie[pre][t^1];
now=trie[now][t],pre=trie[pre][t];
} apr[now]=apr[pre]+1;
}
inline int Que_Max(int x,int l,int r){
r=root[r],l=root[l]; ri ret=0;
for(ri i=24;i>=0;i--){
ri t=(x>>i)&1;
if(apr[trie[r][t^1]] > apr[trie[l][t^1]])
ret|=(1<<i),r=trie[r][t^1],l=trie[l][t^1];
else r=trie[r][t],l=trie[l][t];
} return ret;
}
};
struct Balanced_Trie{
//? 听说Trie可以当平衡树用(
//但读者自证不难:我不会
};
int main()
{
Sync(); //以下是应用上面的模板通过ExKMP模板题的示例 below is an example , using structs above to solve the ExKMP Template Problem.
cin>>exkmp.a,cin>>exkmp.b;
exkmp.pres(),exkmp.ExKMP();
unsigned long long a=0,b=0;
for(int i=0;i<exkmp.lenb;i++)
a^=(unsigned long long)(i+1)*(exkmp.nxt[i]+1);
for(int i=0;i<exkmp.lena;i++)
b^=(unsigned long long)(i+1)*(exkmp.zf[i]+1);
cout<<a<<'\n'<<b;
return 0;
}

浙公网安备 33010602011771号