• Luogu P4465 [国家集训队]JZPSTR


    shift-and 字符串匹配雾

    我们用 bitset 按位维护字符是否出现过。每次按照偏移量 & 起来即可求出哪些位置出现过子串。

    (成功手写 bitset 写挂)

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define R register int
    using namespace std;
    namespace Luitaryi {
    char B[1<<23],*E=B,*T=B;
    #define getchar() (E==T&&(T=(E=B)+fread(B,1,1<<23,stdin),E==T)?EOF:*E++)
    inline int g() { R x=0,f=1;
      register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
      do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
    } 
    inline void g(char* str) { 
      register char s; while(!isdigit(s=getchar()));
      do *str++=s; while(isdigit(s=getchar())); *str='';
    } 
    const int N=1000010;
    #define u32 unsigned 
    #define popcount(x) (tab[x>>16]+tab[x&65535])
    int Cas,t,n,m,op,tab[65536];
    char s[N];
    struct bitset {
      u32 v[N/32+5];
      inline void reset() {for(R i=0;i<=t;++i) v[i]=0;}
      inline bool test(int x) {return v[x>>5]>>(x&31)&1;}
      inline void set(int x,bool y) 
        {if((v[x>>5]>>(x&31)&1)^y) v[x>>5]^=1u<<(x&31);}
      inline void flip(int x) {v[x>>5]^=1u<<(x&31);}
      inline void shl(int l,int len) {
        R L=len>>5,res=len&31,rev=(32-res)&31,p=l>>5;
        for(R i=l,lim=(p<<5)+31;i<=lim;++i) set(i,test(i+len));
        for(R i=p+1;i<=t;++i) {
          v[i]=v[i+L]>>res;
          if(rev) v[i]|=v[i+L+1]<<rev;
        } 
      }
      inline void shr(int l,int len) {
        R L=len>>5,res=len&31,rev=(32-res)&31,p=l>>5;
        v[t+L+1]=0;
        for(R i=t;i>p;--i) {
          if(rev) v[i+L+1]|=v[i]>>rev;
          v[i+L]=v[i]<<res;
        } for(R i=(p<<5)+31;i>=l;--i) set(i+len,test(i));
      }
      inline void cpy(int l,int r,const bitset& src) 
        {for(R i=l;i<=r;++i) v[i]=src.v[i];}
      inline void And(int l,int r,const bitset& src) 
        {for(R i=l;i<=r;++i) v[i]&=src.v[i];}
      inline void shift(int l,int r) {//左移一位
        for(R i=r;i>=l;--i) {
          v[i]<<=1;
          if(i&&(v[i-1]>>31&1)) v[i]|=1;
        }
      }
      inline int count(int l,int r) {
        R p=l>>5,q=r>>5,ret=0;
        if(p==q) {
          for(R i=l;i<=r;++i) 
            if(v[p]>>(i&31)&1) ++ret; 
          return ret;
        }
        for(R i=p+1;i<q;++i) ret+=__builtin_popcount(v[i]);
        for(R i=l,lim=(p<<5)+31;i<=lim;++i) if(v[p]>>(i&31)&1) ++ret;
        for(R i=q<<5;i<=r;++i) if(v[q]>>(i&31)&1) ++ret;
        return ret;
      }
    }f[10],S;
    inline void get() {
      g(s),m=strlen(s);
      for(R i=0;i<m;++i) s[i]-='0';
    }
    inline void ins(int p) {
      for(R i=0;i<10;++i) f[i].shr(p,m);
      for(R i=0;i<10;++i) for(R j=0;j<m;++j)
        f[i].set(p+j,s[j]==i);
      n+=m,t=n>>5;
    }
    inline void del(int l,int r) {
      if(l==r) return ;
      n-=r-l,t=n>>5;
      for(R i=0;i<10;++i) f[i].shl(l,r-l);
    }
    inline int ask(int l,int r) {
      if(r-l<m) return 0; --r;
      R LL=l>>5,RR=r>>5;
      S.cpy(LL,RR,f[s[0]]);
      for(R i=1;i<m;++i) 
        S.shift(LL,RR),S.And(LL,RR,f[s[i]]);
      return S.count(l+m-1,r);
    }
    inline void main() {
      Cas=g(); for(R i=1,op,x,y;i<=Cas;++i) {
        op=g(),x=g();
        if(op==0) get(),ins(x);
        if(op==1) y=g(),del(x,y);
        if(op==2) y=g(),get(),printf("%d
    ",ask(x,y));
      }
    }
    } signed main() {Luitaryi::main(); return 0;}
    

    2020.01.16

  • 相关阅读:
    拼接数组的几种方法
    小议GetHashCode()方法
    如何在窗体间传递数据!
    设置TextBox控件的滚动条位置
    关于Console.Read()方法的一些误解!
    从内存布局角度谈谈值类型和引用类型!
    在Windows线程中模拟其他用户上下文!
    将文本插入TextBox控件的光标位置!
    用C#实现屏幕键盘!
    CLR的程序集定位算法
  • 原文地址:https://www.cnblogs.com/Jackpei/p/12202787.html
Copyright © 2020-2023  润新知