字符串基础

字符串基础

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

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

    dpi,j 表示枚举到第 i 个氨基酸,匹配到 j 位的方案数。

    有转移:

    dpi,j=kaidp[i1][jli,k]

    li,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

    dpi,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 开始。

考虑递推。

首先 nxti+1nxti1,因为最多就是扩展一个。

s[nxti]=s[i+1] 时,nxti+1=nxti

考虑 s[nxti]s[i+1] 时,此时 nxti+1 的最大可能值就是 nxtnxti1

可以参考 oi-wiki

注意,为方便调用,实际使用时 nxti 其实存储在 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. 动物园

    好像可以建树,但其实直接筛出 12sizeborder 长度再暴力跳即可。

    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

    用栈存,该删时出栈,注意要存一下在 ij 的位置。

    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 长度。

    求完最大 bordernxt)后直接跳。

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

    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 @   5k_sync_closer  阅读(23)  评论(1编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示