LGP13274 [NOI 2025] 三目运算符 学习笔记
LGP13274 [NOI 2025] 三目运算符 学习笔记
前言
大家好,我是24-25赛季湖柏三倍正式队线选手。
才饮吹布尔,又食贴纳瑞。
\(n\le 10^4\) 样例横渡,极目 \(\text{AC}\) 舒……
国赛 \(\texttt{d2t1}\) \(\text{VS}\) 省选 \(\texttt{d2t1}\),你知道吗?
题意简述
对于一个长度为 \(n\) (\(n \geq 3\)) 的01串 \(S = s_1 \ldots s_n\),定义变换 \(T = f(S) = t_1 \ldots t_n\) 如下:
若串 \(T\) 满足 \(f(T) = T\),则称 \(T\) 为变换 \(f\) 的不动点。
记 \(f^k(S)\) 为 \(S\) 经过 \(k\) 次变换得到的串。特别地,记 \(f^0(S)=S\)。求最小的自然数 \(k\),使得 \(f^k(S)\) 为变换 \(f\) 的不动点,即满足 \(f^{k+1}(S) = f^k(S)\) 的最小的自然数 \(k\)。可以证明,一定存在自然数 \(k\) 使得 \(f^k(S)\) 为变换 \(f\) 的不动点。
还有 \(q\) 次修改操作。第 \(i\) 次修改会将区间 \([l_i,r_i]\) 01反转。对初始时及每次修改后的字符串 \(S\),都求出最小的 \(k\)。
做法解析
\(f(S)_i\) 只取决于 \(S_{[i-2,i]}\)。手玩分析问题。你发现在 \(8\) 个三位长的01串中,只有 \(2\) 个会造成 \(f(S)_i=S_i\):\(110\) 和 \(101\)。
进一步手玩分析。\(\texttt{101}\) 一步变成 \(\texttt{XY0}\) 就独自美丽了,但 \(\texttt{110}\) 不一样,它会强势地把后面的东西都撅了。\(\texttt{110X}\) 在变换后会变成 \(\texttt{Y110}\),相当于往右走了一格。
所以答案已经呼之欲出了。\(ans=\max([E],(n-j+1))\)。其中 \(E\) 为 \(101\) 子串的存在性,\(j\) 为最靠左的 \(110\) 的 \(0\) 的下标。
小朋友,告诉我这道题要怎么维护信息啊?对啦,当然是用我们最可爱的线段树啦!
- 维护区间内 \(\texttt{110}\)、\(\texttt{101}\) 的存在性。
- 因为有区间反转所以也维护 \(\texttt{001}\)、\(\texttt{010}\) 的存在性。暂且称以上这四个是关键串。
- 由于你需要
pushup,所以你需要维护区间前缀 \(\texttt{1}\)、\(\texttt{0}\)、\(\texttt{11}\)、\(\texttt{10}\),这些可能在你pushup时组成关键串的后半部分。 - 同理维护区间后缀 \(\texttt{0}\)、\(\texttt{1}\)、\(\texttt{00}\)、\(\texttt{01}\)、\(\texttt{10}\)、\(\texttt{11}\)。这些可能在你
pushup时组成关键串的前半部分。
就这样。写就完了。
代码实现
我们不缺线段树这点空间,所以不妨直接这么开,让01串对应二进制意义。
#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxN=8e5+5,isk[8]={0,1,1,0,0,1,1,0};
int N,M,A[MaxN];
struct SegTree{
int cl[MaxN<<2],cr[MaxN<<2],cmid[MaxN<<2],tag[MaxN<<2],exist[MaxN<<2][8];
int pre1[MaxN<<2][2],pre2[MaxN<<2][4],suf1[MaxN<<2][2],suf2[MaxN<<2][4];
int ls(int u){return u<<1;}
int rs(int u){return (u<<1)|1;}
void clearnode(int u){
cl[u]=cr[u]=cmid[u]=tag[u]=pre1[u][0]=pre1[u][1]=suf1[u][0]=suf1[u][1]=0;
fill(exist[u],exist[u]+8,0);fill(pre2[u],pre2[u]+4,0),fill(suf2[u],suf2[u]+4,0);
}
void pushup(int u){
int clen=cr[u]-cl[u]+1;
if(clen<4){
for(int i=0;i<4;i++)suf2[u][i]=suf1[ls(u)][i>>1]&&pre1[rs(u)][i&1];
if(clen==2)memcpy(pre2[u],suf2[u],sizeof(suf2[u]));
else for(int i=0;i<4;i++)pre2[u][i]=pre2[ls(u)][i];
}
for(int i=0,flag;i<8;i++){
if(i<2)pre1[u][i]=pre1[ls(u)][i],suf1[u][i]=suf1[rs(u)][i];
if(i<4&&clen>=4)pre2[u][i]=pre2[ls(u)][i],suf2[u][i]=suf2[rs(u)][i];
if(!isk[i])continue;flag=0;
exist[u][i]=exist[ls(u)][i]||exist[rs(u)][i];
exist[u][i]|=(suf1[ls(u)][i>>2]&&pre2[rs(u)][i&3]);
exist[u][i]|=(suf2[ls(u)][i>>1]&&pre1[rs(u)][i&1]);
}
}
void build(int u,int l,int r){
clearnode(u),cl[u]=l,cr[u]=r;if(l==r){pre1[u][A[l]]=suf1[u][A[l]]=1;return;}
int mid=(l+r)>>1;cmid[u]=mid;build(ls(u),l,mid),build(rs(u),mid+1,r);pushup(u);
}
void maketag(int u){
tag[u]^=1;swap(pre1[u][0],pre1[u][1]),swap(suf1[u][0],suf1[u][1]);
for(int i=0;i<2;i++)swap(pre2[u][i],pre2[u][3-i]),swap(suf2[u][i],suf2[u][3-i]);
for(int i=0;i<4;i++)if(isk[i])swap(exist[u][i],exist[u][7-i]);
}
void pushdown(int u){if(tag[u])maketag(ls(u)),maketag(rs(u)),tag[u]=0;}
void update(int u,int dl,int dr){
if(dl<=cl[u]&&cr[u]<=dr){maketag(u);return;}
pushdown(u);
if(dl<=cmid[u])update(ls(u),dl,dr);
if(dr>cmid[u])update(rs(u),dl,dr);
pushup(u);
}
int binser(int u){
if(!exist[u][6])return 0;
if(cr[u]-cl[u]+1==3&&exist[u][6])return cr[u];
pushdown(u);int res=binser(ls(u));if(res)return res;
if(suf2[ls(u)][3]&&pre1[rs(u)][0])return cmid[u]+1;
if(suf1[ls(u)][1]&&pre2[rs(u)][2])return cmid[u]+2;
res=binser(rs(u));return res;
}
}SgT;
int X,Y;char ch;
int solve(){
int res=SgT.binser(1);
if(res)return N-res+1;
return SgT.exist[1][5];
}
lolo ans;
void mian(){
readis(N,M);
for(int i=1;i<=N;i++)scanf(" %c",&ch),A[i]=ch-'0';
SgT.build(1,1,N);ans=solve();
for(int i=1;i<=M;i++)readis(X,Y),SgT.update(1,X,Y),ans^=1ll*(i+1)*solve();
writil(ans);
}
int Tpn,Tcn;
int main(){
readis(Tpn,Tcn);
while(Tcn--)mian();
return 0;
}
后记
:“其实,\(\text{NOI}\) \(\texttt{d2t1}\) 设定上是不要求难度高于提高组的。”
:“是吗……为什么要告诉我这个。”
:“没什么……只是想让你知道而已。”
——《铁打的距离感》
笑点解析:主播的嗯哦哎2025连铁都没得打。是因为主播不想打吗?
浙公网安备 33010602011771号