1 条题解
-
0
题目分析
非常有意思的思维题。
首先我们弱化题目,考虑不用反转怎么做。
我们考虑相邻的 个数什么情况下会变化: 同时成立。显然这种情况只有 。
我们考虑目前已经有一个不动的前缀 和字符 。我们只关心 的最后 个字符,不妨设为 。
如果 构成 ,显然下一时刻 ,由于 ,所以下一时刻无论 从哪里转移过来 一定也是 。考虑 后面的一个字符 , 中 从前面的 转移过来,即 。这样 ,依次向后。假设一开始 的下标是 那么会变化 次。
考虑 构成 ,下一次变化会变为 。不会继续变化。
提示:上面两种情况 不变是基于已经有一个不动的前缀的假设。
接下来考虑前缀变化对 的影响。
显然有 应该优先考虑,因为它的贡献更大。前面的一个 会覆盖后面一个的贡献,所以取最靠前的。考虑 对其的影响:样例 #1 的第一组测试数据阐释了这种情况:我们假定串是 ,经过一次变换之后变为 ,不会有新的影响,不需要考虑。
由于 已经优先考虑, 不继续考虑其影响。对于 显然变换之后不会形成新的 (有连续两个 )。
综上所述:静态查询的方案是如果有子串 ,取其第一次出现的位置 ,答案是 ;如果有 ,答案是 ;否则答案是 。
考虑如何动态修改——线段树维护即可。
需要维护节点的最前、后的一、二位信息,以便合并。标记是反转。查询直接对根节点信息考虑上述静态方案即可。代码有点长。
时间复杂度 。
代码实现
#include<bits/stdc++.h> #define int long long using namespace std; constexpr int N=4e5+1,Inf=0x3f3f3f3f3f3f3f3fll; int id,T,n,q,a[N],tot,rt,ans; string s; struct SegmentTreeNode{ int l,r,ls,rs,pre0,pre1,suf0,suf1,pre00,pre01,pre10,pre11,suf00,suf01,suf10,suf11,is101,is010,first110,first001,tag;//101,110 SegmentTreeNode(int l=0,int r=0):l(l),r(r),ls(0),rs(0),tag(0){ pre0=pre1=suf0=suf1=pre00=pre01=pre10=pre11=suf00=suf01=suf10=suf11=0; is101=is010=0,first110=first001=Inf; } }f[N<<1]; void pushup(int cur){ f[cur].pre0=f[f[cur].ls].pre0, f[cur].pre1=f[f[cur].ls].pre1; f[cur].suf0=f[f[cur].rs].suf0, f[cur].suf1=f[f[cur].rs].suf1; f[cur].pre00=f[cur].pre01=f[cur].pre10=f[cur].pre11=f[cur].suf00=f[cur].suf01=f[cur].suf10=f[cur].suf11=0; f[cur].is101=f[cur].is010=0,f[cur].first110=f[cur].first001=Inf; if(f[cur].r-f[cur].l+1==1) return; if(f[f[cur].ls].r-f[f[cur].ls].l+1==1){ f[cur].pre00=f[f[cur].ls].pre0&f[f[cur].rs].pre0, f[cur].pre01=f[f[cur].ls].pre0&f[f[cur].rs].pre1, f[cur].pre10=f[f[cur].ls].pre1&f[f[cur].rs].pre0, f[cur].pre11=f[f[cur].ls].pre1&f[f[cur].rs].pre1; } else{ f[cur].pre00=f[f[cur].ls].pre00, f[cur].pre01=f[f[cur].ls].pre01, f[cur].pre10=f[f[cur].ls].pre10, f[cur].pre11=f[f[cur].ls].pre11; } if(f[f[cur].rs].r-f[f[cur].rs].l+1==1){ f[cur].suf00=f[f[cur].ls].suf0&f[f[cur].rs].suf0, f[cur].suf01=f[f[cur].ls].suf0&f[f[cur].rs].suf1, f[cur].suf10=f[f[cur].ls].suf1&f[f[cur].rs].suf0, f[cur].suf11=f[f[cur].ls].suf1&f[f[cur].rs].suf1; } else{ f[cur].suf00=f[f[cur].rs].suf00, f[cur].suf01=f[f[cur].rs].suf01, f[cur].suf10=f[f[cur].rs].suf10, f[cur].suf11=f[f[cur].rs].suf11; } f[cur].is101=f[cur].is010=0,f[cur].first110=f[cur].first001=Inf; if(f[cur].r-f[cur].l+1==2) return; f[cur].is101=(f[f[cur].ls].is101|f[f[cur].rs].is101), f[cur].is010=(f[f[cur].ls].is010|f[f[cur].rs].is010); if(f[f[cur].ls].suf1&&f[f[cur].rs].pre01||f[f[cur].ls].suf10&&f[f[cur].rs].pre1) f[cur].is101=1; if(f[f[cur].ls].suf0&&f[f[cur].rs].pre10||f[f[cur].ls].suf01&&f[f[cur].rs].pre0) f[cur].is010=1; f[cur].first110=min(f[f[cur].ls].first110,f[f[cur].rs].first110), f[cur].first001=min(f[f[cur].ls].first001,f[f[cur].rs].first001); if(f[f[cur].ls].suf11&&f[f[cur].rs].pre0) f[cur].first110=min(f[cur].first110,f[f[cur].ls].r-1); if(f[f[cur].ls].suf00&&f[f[cur].rs].pre1) f[cur].first001=min(f[cur].first001,f[f[cur].ls].r-1); if(f[f[cur].ls].suf1&&f[f[cur].rs].pre10) f[cur].first110=min(f[cur].first110,f[f[cur].ls].r); if(f[f[cur].ls].suf0&&f[f[cur].rs].pre01) f[cur].first001=min(f[cur].first001,f[f[cur].ls].r); return; } void flip(int cur){ swap(f[cur].pre0,f[cur].pre1),swap(f[cur].suf0,f[cur].suf1); swap(f[cur].pre00,f[cur].pre11),swap(f[cur].pre01,f[cur].pre10), swap(f[cur].suf00,f[cur].suf11),swap(f[cur].suf01,f[cur].suf10); swap(f[cur].is010,f[cur].is101),swap(f[cur].first110,f[cur].first001); f[cur].tag^=1; return; } void pushdown(int cur){ if(f[cur].tag){ flip(f[cur].ls),flip(f[cur].rs); f[cur].tag^=1; } return; } void build(int l,int r,int&cur){ f[cur=(++tot)]=SegmentTreeNode(l,r); if(l==r){ if(a[l]) f[cur].pre1=f[cur].suf1=1; else f[cur].pre0=f[cur].suf0=1; return; } int mid=(l+r)>>1; build(l,mid,f[cur].ls),build(mid+1,r,f[cur].rs); return pushup(cur); } void modify(int l,int r,int cur){ if(l<=f[cur].l&&f[cur].r<=r) return flip(cur); pushdown(cur); int mid=(f[cur].l+f[cur].r)>>1; if(l<=mid) modify(l,r,f[cur].ls); if(mid<r) modify(l,r,f[cur].rs); return pushup(cur); } int query(){ int tmp; if((tmp=f[rt].first110)!=Inf) return n-tmp-1; else if(f[rt].is101) return 1; else return 0; }/* void debug(){ cerr<<query()<<' '<<f[rt].first001<<'\n'; return; }*/ void Main(){ tot=0; cin>>n>>q>>s; for(int i=1;i<=n;i++) a[i]=(s[i-1]^48); build(1,n,rt); ans=query(); // debug(); for(int i=1,l,r;i<=q;i++){ cin>>l>>r; modify(l,r,rt); ans^=(i+1)*query(); // debug(); } cout<<ans<<'\n'; return; } signed main(){ ios::sync_with_stdio(0); cin.tie(nullptr),cout.tie(nullptr); for(cin>>id>>T;T;--T) Main(); return 0; }
- 1
信息
- ID
- 2388
- 时间
- 2000ms
- 内存
- 512MiB
- 难度
- 8
- 标签
- 递交数
- 28
- 已通过
- 6
- 上传者