[压位 手写bitset] BZOJ 2628 JZPSTR

Hillan说 怎么暴力怎么写
然后我们就每个数码用个bitset存一下就好了
因为bitset太难操作 自己手写一个
详见代码

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef unsigned long long ull;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
inline int read(char *s){
  char c=nc(); int len=0;
  for (;!(c>='0' && c<='9');c=nc());
  for (;c>='0' && c<='9';s[++len]=c,c=nc()); return len;
}

const int N=2000500;
const int B=64;
ull ans[N/B];

struct Bitset{
  ull s[N/B]; int len;
  void set0(int x) { s[x>>6]&=~(1llu<<x); }
  void set1(int x) { s[x>>6]|=1llu<<x; }
  bool val(int x) { return s[x>>6]>>x&1; }
  void cpy(int x,int y) { if (val(y)) set1(x); else set0(x); }
  void insert(int x,int y){
    len+=y;
    int r=(len-1)>>6,l=(x+y)>>6;
    int a=y>>6,b=y&63,c=64-b;
    if (b)
      for (;r>l;r--) s[r]=s[r-a-1]>>c|s[r-a]<<b;
    else
      for (;r>l;r--) s[r]=s[r-a];
    int p=((r+1)<<6)-1;
    for (;p>=x+y;p--) cpy(p,p-y);
  }
  void erase(int x,int y){
    len-=y;
    for (;x<len && (x&63);x++) cpy(x,x+y);
    if (x>=len) {
      for (x=len;x&63;x++) set0(x);
      for (int i=(x>>6);s[i];i++) s[i]=0;
      return;
    }
    int l=x>>6,r=(len-1)>>6;
    int a=y>>6,b=y&63,c=64-b;
    if (b)
      for (;l<=r;l++) s[l]=s[l+a]>>b|s[l+a+1]<<c;
    else
      for (;l<=r;l++) s[l]=s[l+a];
    for (;s[l];l++) s[l]=0;
  }
  void extra(int x,int y){
    int r=(y-1)>>6;
    int a=x>>6,b=x&63,c=64-b;
    if (b)
      for (int i=0;i<=r;++i) ans[i]&=s[a+i]>>b|s[a+i+1]<<c;
    else
      for (int i=0;i<=r;++i) ans[i]&=s[a+i];
  }
  void print(){
    for (int i=0;i<((len-1)>>6);i++)
      printf("%llu\n",s[i]);
  }
}bit[10];

char s[N];

int cnt[65536];

inline void Pre(){
  for (int i=1;i<65536;i++)
    cnt[i]=cnt[i>>1]+(i&1);
}
inline int count(ull x){
  return cnt[x&65535]+cnt[(x>>16)&65535]+cnt[(x>>32)&65535]+cnt[(x>>48)&65535];
}

int main(){
  int ncnt=0;
  int Q,order,x,y,len;
  freopen("Enchanters.in","r",stdin);
  freopen("Enchanters.out","w",stdout);
  read(Q); Pre();
  while (Q--){
    read(order); read(x);
    if (order==0){
      len=read(s); y=len;
      for (int t=0;t<10;t++){
    bit[t].insert(x,y);
    for (int i=1;i<=len;i++)
      if (s[i]==t+'0')
        bit[t].set1(x+i-1);
      else
        bit[t].set0(x+i-1);
      }
    }else if (order==1){
      read(y); y-=x;
      for (int t=0;t<10;t++)
    bit[t].erase(x,y);
    }else{
      if ((++ncnt)==54)
    ncnt=54;
      read(y); y-=x;
      len=read(s);
      if (y<len){ printf("0\n"); continue; }
      int length=y-len+1,p=(length-1)>>6,Ans=0;
      for (int i=0;i<=p;i++) ans[i]=-1;
      for (int i=1;i<=len;i++)
    bit[s[i]-'0'].extra(x+i-1,length);
      for (int i=0;i<p;i++)
    Ans+=count(ans[i]);
      if (length&63)
    Ans+=count(ans[p]&((1llu<<(length&63))-1));
      else
    Ans+=count(ans[p]);
      printf("%d\n",Ans);
    }   
  }
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值