字符串基础

字符串基础

拖了挺久的了,趁集训推完了。

Hash

个人感觉变化挺多的。

类似进制数。

多和二分结合。

核心代码
class HASH{
public:
    int HS[N];
    inline void mk(char* s){For(i,0,strlen(s)-1,1) HS[i+1]=(1ll*HS[i]*P%MOD+s[i])%MOD;}
    inline int get(int l,int r){return (HS[r]-1ll*HS[l-1]*pw[r-l+1]%MOD+MOD)%MOD;}
}ha[N],hb[N];
  1. Bovine Genomics

    双指针。

    有点滑动窗口的感觉。

    \(l,r\) 枚举区间,合法 \(l++\),非法 \(r++\),合法时取个 \(min\) 即为答案。

    CODE
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long llt;
    typedef unsigned long long ull;
    const int N=503,MOD=10000132,P=131;
    #define For(i,a,b,c) for(register int $L=a,$R=b,$C=c,$D=(0<=$C)-($C<0),i=$L;i*$D<=$R*$D;i+=$C)
    int n,m,pw[N];
    char ls[N];
    int pd[MOD];
    
    namespace IO{
        template<typename T> inline void write(T x){
            static T st[45];T top=0;if(x<0)x=~x+1,putchar('-');
            do{st[top++]=x%10;}while(x/=10);while(top)putchar(st[--top]^48);
        }
        template<typename T> inline void read(T &x){
            char s=getchar();x=0;bool pd=false;while(s<'0'||'9'<s){if(s=='-') pd=true;s=getchar();}
            while('0'<=s&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();if(pd) x=-x;
        }
    }
    namespace IO{
        template<typename T,typename... Args> inline void read(T& x,Args&... args){read(x);read(args...);}
        inline void write(const char c){putchar(c);}
        inline void write(const char *c){int len=strlen(c);For(i,0,len-1,1) putchar(c[i]);}
        template<typename T> inline void Write(T x){write(x);putchar(' ');}
        inline void Write(const char c){write(c);if(c!='\n') putchar(' ');}
        inline void Write(const char *c){write(c);if(c[strlen(c)-1]!='\n') putchar(' ');}
        template<typename T,typename... Args> inline void write(T x,Args... args){write(x);write(args...);}
        template<typename T,typename... Args> inline void Write(T x,Args... args){Write(x);Write(args...);}
    }
    using namespace IO;
    class HASH{
    public:
        int HS[N];
        inline void mk(char* s){For(i,0,strlen(s)-1,1) HS[i+1]=(1ll*HS[i]*P%MOD+s[i])%MOD;}
        inline int get(int l,int r){return (HS[r]-1ll*HS[l-1]*pw[r-l+1]%MOD+MOD)%MOD;}
    }ha[N],hb[N];
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("in_out/in.in","r",stdin);
        freopen("in_out/out.out","w",stdout);
    #endif
        pw[0]=1;
        For(i,1,N-1,1) pw[i]=1ll*pw[i-1]*P%MOD;
        read(n,m);
        For(i,1,n,1) scanf("%s",ls),ha[i].mk(ls);
        For(i,1,n,1) scanf("%s",ls),hb[i].mk(ls);
        int l=1,r=1,cnt=0,ans=0x3f3f3f3f;
        while(r<=m){
            cnt++;
            For(i,1,n,1) pd[ha[i].get(l,r)]=cnt;
            For(i,1,n,1) if(pd[hb[i].get(l,r)]==cnt){r++;goto End;}
            ans=min(ans,r-l+1);
            l++;
            End:;
        }
        write(ans);
    }
    

    也可以二分答案。

  2. 「TJOI2018」str

    考虑 \(dp\)

    \(dp_{i,j}\) 表示枚举到第 \(i\) 个氨基酸,匹配到 \(j\) 位的方案数。

    有转移:

    \[dp{i,j}=\sum\limits_{k\in 可匹配的a_i碳基}dp[i-1][j-l_{i,k}] \]

    \(l_{i,k}\) 表示第 \(i\) 个氨基酸,第 \(k\) 个碳基的长度。

    匹配直接 \(hash\) 判即可。

    CODE
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long llt;
    typedef unsigned long long ull;
    const int N=1e5+3,MOD=1e9+7,MOD1=1000000123,MOD2=1000000321,P=131;
    #define For(i,a,b,c) for(register int $L=a,$R=b,$C=c,$D=(0<=$C)-($C<0),i=$L;i*$D<=$R*$D;i+=$C)
    int dp[102][N],n;
    char s[N],a[N];
    struct DB{
        int F,S;
        bool operator==(DB x)const{return x.F==F&&x.S==S;}
        DB operator+(DB x)const{return {(F+x.F)%MOD1,(S+x.S)%MOD2};}
        DB operator-(DB x)const{return {(F-x.F+MOD1)%MOD1,(S-x.S+MOD2)%MOD2};}
        DB operator*(DB x)const{return {1ll*F*x.F%MOD1,1ll*S*x.S%MOD2};}
    }pw[N];
    
    namespace IO{
        template<typename T> inline void write(T x){
            static T st[45];T top=0;if(x<0)x=~x+1,putchar('-');
            do{st[top++]=x%10;}while(x/=10);while(top)putchar(st[--top]^48);
        }
        template<typename T> inline void read(T &x){
            char s=getchar();x=0;bool pd=false;while(s<'0'||'9'<s){if(s=='-') pd=true;s=getchar();}
            while('0'<=s&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();if(pd) x=-x;
        }
    }
    namespace IO{
        template<typename T,typename... Args> inline void read(T& x,Args&... args){read(x);read(args...);}
        inline void write(const char c){putchar(c);}
        inline void write(const char *c){int len=strlen(c);For(i,0,len-1,1) putchar(c[i]);}
        template<typename T> inline void Write(T x){write(x);putchar(' ');}
        inline void Write(const char c){write(c);if(c!='\n') putchar(' ');}
        inline void Write(const char *c){write(c);if(c[strlen(c)-1]!='\n') putchar(' ');}
        template<typename T,typename... Args> inline void write(T x,Args... args){write(x);write(args...);}
        template<typename T,typename... Args> inline void Write(T x,Args... args){Write(x);Write(args...);}
    }
    using namespace IO;
    class HASH{
    public:
        DB HS[N];
        inline void mk(char* s){For(i,0,strlen(s)-1,1) HS[i+1]=HS[i]*pw[1]+DB{s[i],s[i]};}
        inline DB get(int l,int r){return HS[r]-HS[l-1]*pw[r-l+1];}
    }cs,ca;
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("in_out/in.in","r",stdin);
        freopen("in_out/out.out","w",stdout);
    #endif
        pw[0]=DB{1,1};
        For(i,1,N-1,1) pw[i]=pw[i-1]*DB{P,P};
        read(n);scanf("%s",s+1);cs.mk(s+1);
        int len=strlen(s+1),ls;read(ls);
        For(i,1,ls,1){
            scanf("%s",a+1);ca.mk(a+1);
            int l=strlen(a+1);
            For(j,l,len,1) if(cs.get(j-l+1,j)==ca.HS[l]) dp[1][j]=(dp[1][j]+1)%MOD;
        }
        For(k,2,n,1){
            int x;read(x);
            For(i,1,x,1){
                scanf("%s",a+1);ca.mk(a+1);
                int l=strlen(a+1);
                For(j,l,len,1) if(cs.get(j-l+1,j)==ca.HS[l]) dp[k][j]=(dp[k][j]+dp[k-1][j-l])%MOD;
            }
        }
        int ans=0;
        For(i,1,len,1) ans=(ans+dp[n][i])%MOD;
        write(ans);
    }
    
  3. 通配符匹配

    依然 \(dp\)

    \(dp_{i,j}=0/1\) 表示第 \(i\) 个通配符匹配到 \(j\) 是否成功。

    对于每一个通配符分段,对于 \(?\) 直接转移,对于 \(*\) 枚举左端点 \(Hash\) 判断。

    CODE
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long llt;
    typedef unsigned long long ull;
    const int N=1e5+3,MOD=1000000321,P=131;
    #define For(i,a,b,c) for(register int $L=a,$R=b,$C=c,$D=(0<=$C)-($C<0),i=$L;i*$D<=$R*$D;i+=$C)
    int pw[N],len[15],pos[15],tot_,n;
    char s[N],a[N];
    bool dp[15][N],q[N];
    
    namespace IO{
        template<typename T> inline void write(T x){
            static T st[45];T top=0;if(x<0)x=~x+1,putchar('-');
            do{st[top++]=x%10;}while(x/=10);while(top)putchar(st[--top]^48);
        }
        template<typename T> inline void read(T &x){
            char s=getchar();x=0;bool pd=false;while(s<'0'||'9'<s){if(s=='-') pd=true;s=getchar();}
            while('0'<=s&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();if(pd) x=-x;
        }
    }
    namespace IO{
        template<typename T,typename... Args> inline void read(T& x,Args&... args){read(x);read(args...);}
        inline void write(const char c){putchar(c);}
        inline void write(const char *c){int len=strlen(c);For(i,0,len-1,1) putchar(c[i]);}
        template<typename T> inline void Write(T x){write(x);putchar(' ');}
        inline void Write(const char c){write(c);if(c!='\n') putchar(' ');}
        inline void Write(const char *c){write(c);if(c[strlen(c)-1]!='\n') putchar(' ');}
        template<typename T,typename... Args> inline void write(T x,Args... args){write(x);write(args...);}
        template<typename T,typename... Args> inline void Write(T x,Args... args){Write(x);Write(args...);}
    }
    using namespace IO;
    class HASH{
    public:
        int HS[N];
        inline void mk(char* s){For(i,0,strlen(s)-1,1) HS[i+1]=(1ll*HS[i]*P%MOD+s[i])%MOD;}
        inline int get(int l,int r){return (HS[r]-1ll*HS[l-1]*pw[r-l+1]%MOD+MOD)%MOD;}
    }hs,ha;
    inline bool scmp(int ls,int rs,int la,int ra){return hs.get(ls,rs)==ha.get(la,ra)||rs<ls;}
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("in_out/in.in","r",stdin);
        freopen("in_out/out.out","w",stdout);
    #endif
        pw[0]=1;
        For(i,1,N-1,1) pw[i]=1ll*pw[i-1]*P%MOD;
        scanf("%s",s+1), strcat(s+1,string("?").c_str()), hs.mk(s+1);
        For(i,1,strlen(s+1),1)
            if(s[i]=='*'||s[i]=='?') pos[++tot_]=i,len[tot_]=i-pos[tot_-1]-1;
        read(n);
        while(n--){
            scanf("%s",a+1), strcat(a+1,string("?").c_str()), ha.mk(a+1);
            memset(dp,0,sizeof dp);
            int alen=strlen(a+1); dp[0][0]=1;
            For(i,1,tot_,1){
                memset(q,0,sizeof q);
                For(j,len[i],alen,1){
                    q[j]=(dp[i-1][j-len[i]]&&scmp(pos[i]-len[i],pos[i]-1,j-len[i]+1,j))||q[j-1];
                    // cout<<'q'<<' '<<q[j]<<' '<<dp[i-1][j-len[i]]<<' '<<pos[i]-len[i]<<' '<<pos[i]-1<<' '<<j-len[i]+1<<' '<<j<<' '<<q[j-1]<<endl;
                }
                For(j,len[i],alen,1){
                    if(s[pos[i]]=='?'){
                        if(j==len[i]) continue;
                        dp[i][j]=(dp[i-1][j-len[i]-1]&&scmp(pos[i]-len[i],pos[i]-1,j-len[i],j-1));
                        // cout<<'x'<<' '<<j<<' '<<dp[i-1][j-len[i]-1]<<' '<<scmp(pos[i]-len[i],pos[i]-1,j-len[i],j-1)<<' ';
                        // Write(pos[i]-len[i],pos[i]-1,j-len[i],j-1,'\n');
                    }
                    else dp[i][j]=q[j];
                    // cout<<j<<' '<<dp[i][j]<<endl;
                }
            }
            if(dp[tot_][alen]) puts("YES");
            else puts("NO");
        }
    }
    

KMP

核心是 \(nxt\)(前缀 \(border\) 长度)

\(s\) 下标从 \(0\) 开始。

考虑递推。

首先 \(nxt_{i+1} - nxt_i \le 1\),因为最多就是扩展一个。

\(s[nxt_i]=s[i+1]\) 时,\(nxt_{i+1} = nxt_i\)

考虑 \(s[nxt_i]\not=s[i+1]\) 时,此时 \(nxt_{i+1}\) 的最大可能值就是 \(nxt_{nxt_i-1}\)

可以参考 oi-wiki

注意,为方便调用,实际使用时 \(nxt_i\) 其实存储在 \(i+1\) 处。

至于匹配,比较简单,就是在不相等时跳 \(nxt\),直接看代码吧(不建议使用 oi-wiki 上的匹配方法)。

核心代码
inline void Nxt(char *s){
    int len=strlen(s),i=0,j=-1;
    nxt[0]=-1;
    For(i,0,len-1,1){
        while(j!=-1&&s[i]!=s[j]) j=nxt[j];
        if(s[i+1]==s[++j]) nxt[i+1]=nxt[j];
        else nxt[i+1]=j;
    }
}

scanf("%s%s",w,s);
Nxt(w);
int ans=0,j=0,lens=strlen(s),lenw=strlen(w);
For(i,0,lens-1,1){
    while(~j&&w[j]!=s[i]) j=nxt[j]; j++;
    if(j==lenw) j=nxt[j],ans++;
}
  1. 动物园

    好像可以建树,但其实直接筛出 \(\le \frac{1}{2}size\)\(border\) 长度再暴力跳即可。

    CODE
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long llt;
    typedef unsigned long long ull;
    #define For(i,a,b,c) for(register int $L=a,$R=b,$C=c,$D=(0<=$C)-($C<0),i=$L;i*$D<=$R*$D;i+=$C)
    const int N=1e6+4,MOD=1000000007;
    int nxt[N],num[N],dp[N];
    char s[N];
    
    namespace IO{
        template<typename T> inline void write(T x){
            static T st[45];T top=0;if(x<0)x=~x+1,putchar('-');
            do{st[top++]=x%10;}while(x/=10);while(top)putchar(st[--top]^48);
        }
        template<typename T> inline void read(T &x){
            char s=getchar();x=0;bool pd=false;while(s<'0'||'9'<s){if(s=='-') pd=true;s=getchar();}
            while('0'<=s&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();if(pd) x=-x;
        }
    }
    namespace IO{
        template<typename T,typename... Args> inline void read(T& x,Args&... args){read(x);read(args...);}
        inline void write(const char c){putchar(c);}
        inline void write(const char *c){int len=strlen(c);For(i,0,len-1,1) putchar(c[i]);}
        template<typename T> inline void Write(T x){write(x);putchar(' ');}
        inline void Write(const char c){write(c);if(c!='\n') putchar(' ');}
        inline void Write(const char *c){write(c);if(c[strlen(c)-1]!='\n') putchar(' ');}
        template<typename T,typename... Args> inline void write(T x,Args... args){write(x);write(args...);}
        template<typename T,typename... Args> inline void Write(T x,Args... args){Write(x);Write(args...);}
    }
    using namespace IO;
    inline void Nxt(char *s){
        int len=strlen(s),i=0,j=-1;
        nxt[0]=-1;
        while(i<len){
            if(j==-1||s[i]==s[j]) nxt[++i]=++j;
            else j=nxt[j];
        }
    }
    inline void Num(char *s){
        int len=strlen(s),i=0,j=-1;
        num[0]=-1;
        while(i<len){
            if(j==-1||s[i]==s[j]&&(j+1)<=((i+1)>>1)) num[++i]=++j;
            else j=nxt[j];
        }
    }
    inline int Ans(int len){
        For(i,1,len,1) dp[i]=dp[nxt[i]]+1;
        llt ans=1;
        For(i,1,len,1) ans=ans*(dp[num[i]]+1)%MOD;
        return ans;
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("in_out/in.in","r",stdin);
        freopen("in_out/out.out","w",stdout);
    #endif
        int t;read(t);
        while(t--){
            scanf("%s",s);
            Nxt(s),Num(s);
            // For(i,1,strlen(s),1) cout<<num[i]<<endl;
            Write(Ans(strlen(s)),'\n');
        }
    }
    
  2. Censoring

    用栈存,该删时出栈,注意要存一下在 \(i\)\(j\) 的位置。

    CODE
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long llt;
    typedef unsigned long long ull;
    #define For(i,a,b,c) for(register int $L=a,$R=b,$C=c,$D=(0<=$C)-($C<0),i=$L;i*$D<=$R*$D;i+=$C)
    const int N=2e6+4;
    int nxt[N],pos[N];
    string s,t;
    stack<int> sta;
    
    namespace IO{
        template<typename T> inline void write(T x){
            static T st[45];T top=0;if(x<0)x=~x+1,putchar('-');
            do{st[top++]=x%10;}while(x/=10);while(top)putchar(st[--top]^48);
        }
        template<typename T> inline void read(T &x){
            char s=getchar();x=0;bool pd=false;while(s<'0'||'9'<s){if(s=='-') pd=true;s=getchar();}
            while('0'<=s&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();if(pd) x=-x;
        }
    }
    namespace IO{
        template<typename T,typename... Args> inline void read(T& x,Args&... args){read(x);read(args...);}
        inline void write(const char c){putchar(c);}
        inline void write(const char *c){int len=strlen(c);For(i,0,len-1,1) putchar(c[i]);}
        template<typename T> inline void Write(T x){write(x);putchar(' ');}
        inline void Write(const char c){write(c);if(c!='\n') putchar(' ');}
        inline void Write(const char *c){write(c);if(c[strlen(c)-1]!='\n') putchar(' ');}
        template<typename T,typename... Args> inline void write(T x,Args... args){write(x);write(args...);}
        template<typename T,typename... Args> inline void Write(T x,Args... args){Write(x);Write(args...);}
    }
    using namespace IO;
    inline void Nxt(string s){
        int len=s.size(),i=0,j=-1;
        nxt[0]=-1;
        while(i<len){
            while(j!=-1&&s[i]!=s[j]) j=nxt[j];
            if(s[++i]==s[++j]) nxt[i]=nxt[j];
            else nxt[i]=j;
        }
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("in_out/in.in","r",stdin);
        freopen("in_out/out.out","w",stdout);
    #endif
        cin>>s>>t;
        Nxt(t);
        int len=t.size(),j=0;
        For(i,0,s.size()-1,1){
            sta.push(i);
            while(~j&&s[i]!=t[j]) j=nxt[j];
            j++; pos[i]=j;
            if(j==len){
                For(j,1,len,1) sta.pop();
                if(sta.empty()) j=0;
                else j=pos[sta.top()];
            }
        }
        stack<int> ls;
        while(!sta.empty()) ls.push(sta.top()),sta.pop();
        while(!ls.empty()) write(s[ls.top()]),ls.pop();
    }
    
  3. OKR-Periods of Words

    本质是求最小 \(border\) 长度。

    求完最大 \(border\)\(nxt\))后直接跳。

    好像可以倍增,类似并查集优化,但本题都不用。

    CODE
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long llt;
    typedef unsigned long long ull;
    #define For(i,a,b,c) for(register int $L=a,$R=b,$C=c,$D=(0<=$C)-($C<0),i=$L;i*$D<=$R*$D;i+=$C)
    const int N=2e6+4;
    int nxt[N],len,pos[N];
    string s;
    stack<int> sta;
    
    namespace IO{
        template<typename T> inline void write(T x){
            static T st[45];T top=0;if(x<0)x=~x+1,putchar('-');
            do{st[top++]=x%10;}while(x/=10);while(top)putchar(st[--top]^48);
        }
        template<typename T> inline void read(T &x){
            char s=getchar();x=0;bool pd=false;while(s<'0'||'9'<s){if(s=='-') pd=true;s=getchar();}
            while('0'<=s&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();if(pd) x=-x;
        }
    }
    namespace IO{
        template<typename T,typename... Args> inline void read(T& x,Args&... args){read(x);read(args...);}
        inline void write(const char c){putchar(c);}
        inline void write(const char *c){int len=strlen(c);For(i,0,len-1,1) putchar(c[i]);}
        template<typename T> inline void Write(T x){write(x);putchar(' ');}
        inline void Write(const char c){write(c);if(c!='\n') putchar(' ');}
        inline void Write(const char *c){write(c);if(c[strlen(c)-1]!='\n') putchar(' ');}
        template<typename T,typename... Args> inline void write(T x,Args... args){write(x);write(args...);}
        template<typename T,typename... Args> inline void Write(T x,Args... args){Write(x);Write(args...);}
    }
    using namespace IO;
    inline void Nxt(string s){
        int j=-1;
        nxt[0]=-1;
        For(i,0,len-1,1){
            while(j!=-1&&s[i]!=s[j]) j=nxt[j];
            nxt[i+1]=++j;
        }
    }
    inline llt Ans(){
        llt ans=0;
        For(i,1,len,1){
            int j=nxt[i];
            while(pos[j]>0) j=pos[j];
            pos[i]=j;
            if(j>0) ans+=(i-j);
        }
        return ans;
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("in_out/in.in","r",stdin);
        freopen("in_out/out.out","w",stdout);
    #endif
        read(len),cin>>s;
        Nxt(s);
        write(Ans());
    }
    
  4. BZOJ1461字符串的匹配

    好题。

    用树状数组 \(log\) 求排名。

    具体就是建值域的树状数组,求前缀和。

    KMP 即可。

    CODE
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long llt;
    typedef unsigned long long ull;
    #define For(i,a,b,c) for(register int i=a;i<=b;i+=c)
    #define For_(i,a,b,c) for(register int i=a;i>=b;i-=c)
    const int N=5e5+3;
    int nxt[N],s[N],t[N],crk[N],n,m,cs,ans,cans[N];
    
    namespace IO{
        template<typename T> inline void write(T x){
            static T st[45];T top=0;if(x<0)x=~x+1,putchar('-');
            do{st[top++]=x%10;}while(x/=10);while(top)putchar(st[--top]^48);
        }
        template<typename T> inline void read(T &x){
            char s=getchar();x=0;bool pd=false;while(s<'0'||'9'<s){if(s=='-') pd=true;s=getchar();}
            while('0'<=s&&s<='9'){x=(x<<1)+(x<<3)+(s^48),s=getchar();}if(pd) x=-x;
        }
    }
    namespace IO{
        template<typename T,typename... Args> inline void read(T& x,Args&... args){read(x);read(args...);}
        inline void write(const char c){putchar(c);}
        inline void write(const char *c){int len=strlen(c);For(i,0,len-1,1) putchar(c[i]);}
        template<typename T> inline void Write(T x){write(x);putchar(' ');}
        inline void Write(const char c){write(c);if(c!='\n') putchar(' ');}
        inline void Write(const char *c){write(c);if(c[strlen(c)-1]!='\n') putchar(' ');}
        template<typename T,typename... Args> inline void write(T x,Args... args){write(x);write(args...);}
        template<typename T,typename... Args> inline void Write(T x,Args... args){Write(x);Write(args...);}
    }
    using namespace IO;
    class Btree{
    private:
        int a[N];
        inline int lowbit(int x){return x&(-x);}
    public:
        inline void Clr(){memset(a,0,sizeof a);}
        inline void Add(int x,int t){For(i,x,N-1,lowbit(i))a[i]+=t;}
        inline int Sum(int x){int s=0;For_(i,x,1,lowbit(i))s+=a[i];return s;}
    }bt;
    inline bool equ(int a,int b){
        return a==bt.Sum(b-1);
    }
    inline void Nxt(){
        int i=1,j=0,l=1;
        nxt[1]=0;
        while(i<=m){
            while(l<=i-j) bt.Add(t[l++],-1);
            if(j&&!equ(crk[j],t[i])) j=nxt[j];
            else bt.Add(t[i],1),nxt[++i]=++j;
        }
        bt.Clr();
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("in_out/in.in","r",stdin);
        freopen("in_out/out.out","w",stdout);
    #endif
        read(n,m,cs);
        For(i,1,n,1) read(s[i]);
        For(i,1,m,1) read(t[i]),bt.Add(t[i],1),crk[i]=bt.Sum(t[i]-1);
        bt.Clr();
        Nxt();
        int i=1,j=1,l=1;
        while(i<=n){
            while(l<=i-j) bt.Add(s[l++],-1);
            if(j&&!equ(crk[j],s[i])) j=nxt[j];
            else{
                if(++j==m) cans[++ans]=l,j=nxt[j];
                bt.Add(s[i++],1);
            }
        }
        write(ans,'\n');
        For(i,1,ans,1) write(cans[i],'\n');
    }
    

trie

挺简单的,感觉重点在 \(01trie\)

可以用于插入、查找字符串、前缀。

\(01trie\) 多用于在一个序列中找一个与一个数异或相同的,多组询问。

也可以求一个序列中两个数异或和中最大的(The XOR Largest Pair)。

做法就是按二进制建 \(trie\),查询时尽可能走不同的路径。

  1. The XOR-longest Path

    边 dfs 边加入,查询即可。

    CODE
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long llt;
    typedef unsigned long long ull;
    #define For(i,a,b,c) for(register int i=a;i<=b;i+=c)
    #define For_(i,a,b,c) for(register int i=a;i>=b;i-=c)
    const int N=2e6+4;
    int n,z[33],ans=-1;
    struct edge{int t,v;};
    vector<edge> to[N];
    bool vis[N];
    
    namespace IO{
        template<typename T> inline void write(T x){
            static T st[45];T top=0;if(x<0)x=~x+1,putchar('-');
            do{st[top++]=x%10;}while(x/=10);while(top)putchar(st[--top]^48);
        }
        template<typename T> inline void read(T &x){
            char s=getchar();x=0;bool pd=false;while(s<'0'||'9'<s){if(s=='-') pd=true;s=getchar();}
            while('0'<=s&&s<='9'){x=(x<<1)+(x<<3)+(s^48),s=getchar();}if(pd) x=-x;
        }
    }
    namespace IO{
        template<typename T,typename... Args> inline void read(T& x,Args&... args){read(x);read(args...);}
        inline void write(const char c){putchar(c);}
        inline void write(const char *c){int len=strlen(c);For(i,0,len-1,1) putchar(c[i]);}
        template<typename T> inline void Write(T x){write(x);putchar(' ');}
        inline void Write(const char c){write(c);if(c!='\n') putchar(' ');}
        inline void Write(const char *c){write(c);if(c[strlen(c)-1]!='\n') putchar(' ');}
        template<typename T,typename... Args> inline void write(T x,Args... args){write(x);write(args...);}
        template<typename T,typename... Args> inline void Write(T x,Args... args){Write(x);Write(args...);}
    }
    using namespace IO;
    inline void Fj(int x){For(i,1,31,1) z[i]=x%2,x/=2;}
    class Trie{
    private:
        int t[N][3],tot_;
    public:
        inline void Add(){
            int rt=0;
            For_(i,31,1,1){
                if(!t[rt][z[i]]) t[rt][z[i]]=++tot_;
                rt=t[rt][z[i]];
            }
        }
        inline int Get(){
            int rt=0,sum=0;
            For_(i,31,1,1){
                if(!t[rt][!z[i]]) rt=t[rt][z[i]];
                else rt=t[rt][!z[i]],sum+=(1<<i-1);
            }
            return sum;
        }
    }tr;
    void dfs(int x,int t){
        vis[x]=1;
        for(edge i:to[x]){
            int y=i.t,v=i.v;
            if(vis[y]) continue;
            int ls=t^v;
            Fj(ls);
            ans=max(ans,tr.Get());
            tr.Add();
            dfs(y,t^v);
        }
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("in_out/in.in","r",stdin);
        freopen("in_out/out.out","w",stdout);
    #endif
        read(n);
        For(i,1,n-1,1){int a,b,v;read(a,b,v),to[a].push_back({b,v}),to[b].push_back({a,v});}
        tr.Add();
        dfs(1,0);
        write(ans);
    }
    
  2. Nikitosh 和异或

    首先考虑对于一段区间的异或和最大。

    显然可以前缀异或,就变成了在区间中找两个数,使其异或和最大。

    \(01trie\) 即可。

    考虑本题。

    可以先预处理处每个前缀和后缀的区间的最大异或和,枚举区间的分割点即可。

    CODE
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long llt;
    typedef unsigned long long ull;
    #define For(i,a,b,c) for(register int i=a;i<=b;i+=c)
    #define For_(i,a,b,c) for(register int i=a;i>=b;i-=c)
    const int N=1e7+4;
    int n,a[N],bg[N],ed[N],ans=-1;
    
    namespace IO{
        template<typename T> inline void write(T x){
            static T st[45];T top=0;if(x<0)x=~x+1,putchar('-');
            do{st[top++]=x%10;}while(x/=10);while(top)putchar(st[--top]^48);
        }
        template<typename T> inline void read(T &x){
            char s=getchar();x=0;bool pd=false;while(s<'0'||'9'<s){if(s=='-') pd=true;s=getchar();}
            while('0'<=s&&s<='9'){x=(x<<1)+(x<<3)+(s^48),s=getchar();}if(pd) x=-x;
        }
    }
    namespace IO{
        template<typename T,typename... Args> inline void read(T& x,Args&... args){read(x);read(args...);}
        inline void write(const char c){putchar(c);}
        inline void write(const char *c){int len=strlen(c);For(i,0,len-1,1) putchar(c[i]);}
        template<typename T> inline void Write(T x){write(x);putchar(' ');}
        inline void Write(const char c){write(c);if(c!='\n') putchar(' ');}
        inline void Write(const char *c){write(c);if(c[strlen(c)-1]!='\n') putchar(' ');}
        template<typename T,typename... Args> inline void write(T x,Args... args){write(x);write(args...);}
        template<typename T,typename... Args> inline void Write(T x,Args... args){Write(x);Write(args...);}
    }
    using namespace IO;
    class Trie{
    private:
        int t[N][3],z[33],tot_;
    public:
        inline void Fj(int x){For(i,1,31,1) z[i]=(x&1),x>>=1;}
        inline void Clr(){memset(t,0,sizeof t),memset(z,0,sizeof z),tot_=0;}
        inline void Add(){
            int rt=0;
            For_(i,32,1,1){
                if(!t[rt][z[i]]) t[rt][z[i]]=++tot_;
                rt=t[rt][z[i]];
            }
        }
        inline int Get(){
            int rt=0,sum=0;
            For_(i,32,1,1){
                if(!t[rt][!z[i]]) rt=t[rt][z[i]];
                else rt=t[rt][!z[i]],sum+=(1<<i-1);
            }
            return sum;
        }
    }tr;
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("in_out/in.in","r",stdin);
        freopen("in_out/out.out","w",stdout);
    #endif
        read(n);tr.Add();
        For(i,1,n,1) read(a[i]),a[i]^=a[i-1];
        For(i,1,n,1) tr.Fj(a[i]),bg[i]=max(bg[i-1],tr.Get()),tr.Add();
        tr.Clr(),tr.Add();
        For_(i,n,1,1) tr.Fj(a[i]),ed[i]=max(ed[i+1],tr.Get()),tr.Add();
        For(i,0,n,1) ans=max(ans,bg[i]+ed[i+1]);
        write(ans);
    }
    
posted @ 2024-01-29 17:29  xrlong  阅读(16)  评论(1编辑  收藏  举报