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='\0';
} 
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\n",ask(x,y));
  }
}
} signed main() {Luitaryi::main(); return 0;}

2020.01.16

猜你喜欢

转载自www.cnblogs.com/Jackpei/p/12202787.html
今日推荐