P13274 [NOI2025] 三目运算符

P13274 [NOI2025] 三目运算符

题意

对于一个长度为 \(n\) (\(n \geq 3\)) 的 01 串 \(S = s_1 \ldots s_n\),定义变换 \(S' = f(S) = s'_1 \ldots s'_n\) 如下:

\[s'_i = \begin{cases} s_i, & i \leq 2, \\ s_i, & i \geq 3 \text{ 且 } s_{i-2} = 0, \\ s_{i-1}, & i \geq 3 \text{ 且 } s_{i-2} = 1. \end{cases}\]

\(Q\) 次修改,问初始及每次修改后,要多少次变换之后,再变换时 \(S'=S\)

每次修改,对区间 \([l,r]\) 反转(不是翻转)。

多测,\(n,q \le 4 \times 10^5\)

思路

肯定是先找变换有什么性质/规律。

然后看看怎么快速对一个串串计算答案,最后再考虑怎么在修改时维护答案。

看每一位的变换,如果每一位都不变,整个串串也都不变。每一位的变换可以按照 \(s_{i-2}\) 分两类。

  • \(s_{i-2}=0\) 时,\(s_i\) 直接不变。
  • \(s_{i-2}=1\) 时,\(s_i = s_{i-1}\)

感觉要处理的就是 \(1\) 了。

手搓一下 1111000011110000011110 之类的例子,不难发现只要存在 11,后面跟着的 0 就会变成 1,即 110 \(\to\) 111

而且 110 前后是什么东西,都不影响它变成 111

其实搓样例也可以,搓一下 11010 还可以发现 101 也很特殊。101 一定可以使得它的第三位变成 0

受到这两个的启发,不妨把所有三位的组合都枚举一下。

因为第三位是否变化,可以仅由前两位完全确定下来。取决于第一位是 \(0/1\) 以及第二位是否与第三位相同。

所以第三位改变,确实只有 101110 两种情况了。

手搓的过程中不难发现,串串总有一个由 110 开始往后一直推 1 的趋势。一个 110 总是创造出新的 110,引起很多推 1 的操作。

反观 101 第三位变成 0 之后并不能引起什么连锁反应。

仔细研究一下,把 110 后两位也枚举出来看看情况:

\[110 \to 111 \to \begin{cases} 11100\to 11110 \to 继续\\ 11101\to 11110 \to 继续\\ 11110\to 继续\\ 11111\to \dots \end{cases} \]

虽然第 \(2\) 种情况中间生成了 101,但是马上又消掉了,所以关键在与 110

答案次数取决于 110 后面要推多少个 1 才结束。

看这个样例:1101101

110001100
111001110
111101111
111110111
111111011
111111101
111111110
111111111

搓一个类似的,我们可以发现答案取决于第一个 110 后面还有多少位。

自己把样例搓完,还能发现 1010100 \(= 1\) 的这种特殊情况。

也就是说,我们要维护第一个 110 的位置。就可以维护答案了。

如果没有 110,就要维护有没有 101

有区间修改,可以用线段树维护,维护区间左右两位是什么情况,第一个 110 的位置,以及有没有 101

维护反转的话,再维护一下 001010 也维护一下就可以了吧。

code

感觉代码会很长啊。

还好吧。

#include<bits/stdc++.h>
#define sf scanf 
#define pf printf  
#define rep(x,y,z) for(int x=y;x<=z;x++) 
#define per(x,y,z) for(int x=y;x>=z;x--) 
using namespace std;
typedef long long ll;
namespace wing_heart {
    constexpr int N=4e5+7;
    int testid;
    int T;
    int n,q;
    char s[N];
    int a[N];
    ll ans;
    struct node {
        int l12,r12,pos110,pos001;
        bool is101,is010;
        bool tg;
    } tr[N<<2];
    void maketag(int l,int r,node &u) {
        if(r-l+1==1) {
            u.l12=u.l12?0:2, u.r12=u.r12?0:1;
            return;
        }
        u.l12=(~u.l12)&3, u.r12=(~u.r12)&3;
        swap(u.pos001,u.pos110);
        swap(u.is010,u.is101);
        u.tg=!u.tg;
    }
    void pushup(int l,int r,node &u,node &ls,node &rs) {
        if(r-l+1==2) {
            u = {ls.l12|rs.r12,ls.l12|rs.r12,N,N,0,0,0};
            return;
        } 
        if(r-l+1==3) {
            int sum=(ls.l12<<1)+rs.r12;
            u = {ls.l12,((ls.l12&1)<<1)|rs.r12,sum==6?l+1:N,sum==1?l+1:N,sum==5,sum==2,0};
            return;
        }
        int sum=(ls.r12<<2)+rs.l12;
        u.l12=ls.l12, u.r12=rs.r12;
        u.pos001=min(ls.pos001,rs.pos001), u.pos110=min(ls.pos110,rs.pos110);
        u.is010=ls.is010||rs.is010, u.is101=ls.is101||rs.is101;
        if(sum>>1==6) u.pos110=min(u.pos110,(l+r)>>1);
        if((sum&7)==6) u.pos110=min(u.pos110,((l+r)>>1)+1);
        if(sum>>1==1) u.pos001=min(u.pos001,(l+r)>>1);
        if((sum&7)==1) u.pos001=min(u.pos001,((l+r)>>1)+1);
        if(sum>>1==5 || (sum&7)==5) u.is101=1;
        if(sum>>1==2 || (sum&7)==2) u.is010=1;
    }
    void pushdown(int u,int l,int r) {
        if(!tr[u].tg) return;
        int mid=(l+r)>>1;
        maketag(l,mid,tr[u<<1]), maketag(mid+1,r,tr[u<<1|1]);
        tr[u].tg=0;
    }
    void build(int u,int l,int r) {
        tr[u]={0,0,0,0,0,0,0};
        if(l==r) {
            tr[u]={a[l]<<1,a[l],N,N,0,0,0};
            return;
        }
        int mid=(l+r)>>1;
        build(u<<1,l,mid), build(u<<1|1,mid+1,r);
        pushup(l,r,tr[u],tr[u<<1],tr[u<<1|1]);
    }
    void init() {
        rep(i,1,n) a[i] = s[i]=='1' ? 1 : 0;
        build(1,1,n);
    }
    void change(int u,int l,int r,int L,int R) {
        if(l>=L && r<=R) {
            maketag(l,r,tr[u]);
            return;
        }
        int mid=(l+r)>>1;
        pushdown(u,l,r);
        if(L<=mid) change(u<<1,l,mid,L,R);
        if(mid+1<=R) change(u<<1|1,mid+1,r,L,R);
        pushup(l,r,tr[u],tr[u<<1],tr[u<<1|1]);
    }
    void clear() {
        ans=0;
    }
    void main() {
        sf("%d%d",&testid,&T);
        while(T--) {
            sf("%d%d",&n,&q);
            clear();
            sf("%s",s+1);
            init();
            if(tr[1].pos110==N) {
                if(tr[1].is101) ans^=1;
            } else {
                ans^=n-tr[1].pos110;
            }
            rep(i,1,q) {
                int l,r;
                sf("%d%d",&l,&r);
                change(1,1,n,l,r);
                if(tr[1].pos110==N) {
                    if(tr[1].is101) ans^=i+1;
                } else {
                    ans^=1ll*(i+1)*(n-tr[1].pos110);
                }
            }
            pf("%lld\n",ans);
        }
    }
}
int main() {
    #ifdef LOCAL 
    freopen("in.txt","r",stdin);
    freopen("my.out","w",stdout);
    #endif 
    wing_heart :: main();
}
posted @ 2025-07-21 18:27  wing_heart  阅读(17)  评论(0)    收藏  举报