字符串乱搞&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;
}
posted @ 2022-01-25 10:10  Neutral1sed  阅读(40)  评论(0)    收藏  举报