洛谷P5522 棠梨煎雪(线段树+状态压缩)
这里是点名被卡的$O(qnlogm)$做法
首先考虑对于两个串$s$和$t$,我们怎么合并得到$ans$(两天的总状态):
1. 若存在$s_i$,$t_i$分别为0,1,则返回无解;
2. 若$s_i=t_i$,则$ans_i=s_i$(这里涵盖了$s_i=t_i=?$的情况);
3. 否则,$s_i$,$t_i$,必定一个为0/1,一个为?,$ans_i$取0/1的那个。
不难发现合并可以用线段树维护,而$s$,$t$也不必存成字符串,直接当成3进制(为了卡常一般用4进制+位运算写)long long存,无解用一个特殊数(比如-1)存,最后答案就是$2^{\text{?的个数}}$。
时间复杂度$O(qnlogm)$,但是由于无解的情况存在所以跑不满。
n方过百万,暴力踩标算
#include<cstdio> #include<cctype> typedef long long ll; const int N=100050; char rB[1<<23],*rS,*rT; inline char gc(){return rS==rT&&(rT=(rS=rB)+fread(rB,1,1<<23,stdin),rS==rT)?EOF:*rS++;} inline char rdc(){ char c=gc(); while(isspace(c))c=gc(); return c; } inline int rdi(){ char c=gc(); while(!isdigit(c))c=gc(); int x=c&15; for(c=gc();isdigit(c);c=gc())x=(x<<3)+(x<<1)+(c&15); return x; } short n; int x,y; ll a[N],sum[N<<2],res; ll merg(ll a,ll b){ if(a==-1||b==-1)return -1; //一个无解则必定无解 ll s=0ll; for(short i=0;i<(n<<1);i+=2)if(((a>>i)&3ll)==2)s|=b&(3ll<<i); else if(((b>>i)&3ll)==2ll||((a>>i)&3ll)==((b>>i)&3ll))s|=a&(3ll<<i); else{s=-1;break;} return s; } void build(int o,int L,int R){ if(L==R)sum[o]=a[L]; else{ int lc=o<<1,rc=lc|1,M=L+R>>1; build(lc,L,M);build(rc,M+1,R); sum[o]=merg(sum[lc],sum[rc]); } } void update(int o,int L,int R){ if(L==R)sum[o]=res; else{ int lc=o<<1,rc=lc|1,M=L+R>>1; if(x<=M)update(lc,L,M); else update(rc,M+1,R); sum[o]=merg(sum[lc],sum[rc]); } } ll ask(int o,int L,int R){ if(x<=L&&y>=R)return sum[o]; int lc=o<<1,rc=lc|1,M=L+R>>1; if(x<=M)if(y>M)return merg(ask(lc,L,M),ask(rc,M+1,R)); else return ask(lc,L,M); else return ask(rc,M+1,R); } inline int query(ll x){ //求方案数 if(x==-1)return 0; int s=1; for(short i=0;i<(n<<1);i+=2)if(((x>>i)&3ll)==2ll)s<<=1; return s; } int main(){ int m,q,i,opt,ans=0; char c; short j; n=rdi();m=rdi();q=rdi(); for(i=1;i<=m;++i){ res=0ll; for(j=0;j<n;++j){ c=rdc(); res=(res<<2)|(c=='?'?2:(c&15)); //把30位压进long long里(正向反向无所谓) } a[i]=res; } build(1,1,m); while(q--){ opt=rdi();x=rdi(); if(!opt){ y=rdi(); ans^=query(ask(1,1,m)); }else if(opt==1){ res=0ll; for(j=0;j<n;++j){ c=rdc(); res=(res<<2)|(c=='?'?2:(c&15)); } update(1,1,m); } } printf("%d",ans); return 0; }