1 条题解
-
0
自动搬运
来自洛谷,原作者为

C1942huangjiaxu
我将终究顺流入大海搬运于
2025-08-24 22:45:50,当前版本为作者最后更新于2024-03-13 20:46:52,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
题目中的操作可以看做:
- 选择 2 个相邻的不同的数并删除。
- 选择 3 个相邻且相同的数,删掉其中 2 个。
那么最终对答案有贡献的 一定是 的子序列。
考虑构建这样一个自动机,每个点 有 两条出边,出边 连向最小的 满足 可以被删除的位置 。
假如 可以被删除,那么所有起点为 终点为 的路径都是一个答案。
但这样不够,我们还要证明,每一个答案串 都可以被自动机匹配上。
考虑构建自动机的过程其实是一个贪心的过程,我们只要证明, 满足 且 奇偶性相同,那么对于所有 满足 可以被删除,则 可以被删除。
证明也很简单,只要证明 可以删除,先把 删到只剩下一个数 ,然后删除 和 即可。
自动机的边数是 的,我们只要建出这个自动机就行了。
以 为例,出边 一定满足 奇偶性不同,下面只考虑奇偶性与 不同的位置是否满足条件。
对于 的出边,找到第一个 即可,中间显然能删完。
对于 的出边,上面已经说明了,若 则 可以被删除,所以找到第一个 满足 的 。
我们要证明所有 , 都不可以删完。
首先 中不存在连续的 个 ,我们把连续的 也都删除到不超过 个,那么相当于是一个 ,,, 交替序列,并且序列的开头和末尾都是 段。
注意到不存在奇偶不同的 满足 ,否则 不是第一个,那么,删除过程中始终会是一个满足不存在 的 ,,, 交替序列。
证明考虑归纳:
删除过程中产生 段的合并,直接贪心把个数减小到不超过 。
删除过程中产生 段的合并,因为不存在 ,即不存在 串,所以一定是 个 的合并,设原先的串为 ,我们删除了 , 是 或 。
可以发现,不论 是什么,删除后的 串奇偶性与原先的 串奇偶性相同,仍然不存在 。因为 段个数比 段多 ,所以最后剩下的一定是 ,即 不能被删除。
时间复杂度 。
代码很好写:
#include<bits/stdc++.h> using namespace std; const int N=5e6+5,P=998244353; int T,n,f[N],nx[N][2],to[N][2],ans; char s[N]; inline void Add(int &x,int y){ if((x+=y)>=P)x-=P; } void solve(){ scanf("%s",s+1); n=strlen(s+1); for(int i=1;i<=n;++i)f[i]=0,s[i]-=48; f[1]=1; for(int i=3;i<=n;i+=2)if(s[i]!=s[1]&&s[i]==s[i-1]){ f[i]=1; break; } for(int i=1;i<3;++i)for(int j=0;j<2;++j)nx[n+i][j]=to[n+i][j]=n+1; for(int i=n;i;--i){ nx[i][0]=nx[i+2][0],nx[i][1]=nx[i+2][1]; to[i][0]=to[i+2][0],to[i][1]=to[i+2][1]; nx[i][s[i]]=i; if(i<n&&s[i]==s[i+1])to[i][s[i]]=i+1; } ans=0; for(int i=1;i<=n;++i)if(f[i]){ Add(f[nx[i+1][s[i]^1]],f[i]); Add(f[to[i][s[i]]],f[i]); if(!(n-i&1)&&(s[i]==s[n]||to[i][s[i]]<=n))Add(ans,f[i]); } printf("%d\n",ans); } int main(){ scanf("%d",&T); while(T--)solve(); return 0; }
- 1
信息
- ID
- 8234
- 时间
- 2000ms
- 内存
- 512MiB
- 难度
- 7
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者