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

Nangu
加 训搬运于
2025-08-24 22:59:58,当前版本为作者最后更新于2024-08-15 13:49:59,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
题意
有两个由
+和-组成的字符串 和 ,你需要进行若干次操作,每次可以将 中一段极长串翻转,满足这个极长串的长度小于其任意一个相邻的极长串的长度。问 是否能经过变换得到 。多组数据。题解
我们从特殊性质开始考虑: 中没有
-。对于 中任意一个极长的、由
-构成的串,我们必须想办法将其翻转。首先有一个接近 的暴力:将所有的极长串用链表连接,每次枚举一段由
+组成的串,判断其右边的串是否能翻转。若能,则将这段串右边、右边的右边的串都删掉,并增加这段串的长度。最后,若不能操作时仍有-,则输出No,否则输出Yes,代码如下:void link(int u,int v){ nxt[u]=v, pre[v]=u; } bool check(){ s[n+1]=t[n+1]='\0'; cnt=0; if(s[1]=='-') cnt=1, siz[1]=0; int tmp=1; rep(i, 2, n+1){ if(s[i]!=s[i-1]) siz[++cnt]=tmp, tmp=1; else ++tmp; } if(cnt%2==0) siz[++cnt]=0; rep(i, 1, cnt-1) link(i, i+1); nxt[cnt]=0; while(nxt[1]){ bool flag=0; for(int i=1, j; nxt[i];){ j=nxt[nxt[i]]; if(siz[j]>siz[nxt[i]] || siz[i]>siz[nxt[i]]){ siz[i]+=siz[j]+siz[nxt[i]]; link(i, nxt[j]); flag=1; } i=j; } if(!flag) break; } return !nxt[1]; }这段代码在随机数据下的复杂度应该是 ,仅当 存在类似
--+--+--+-++的串时,复杂度退化为 。因此考虑添加一个优化:当一次翻转成功时,我们回退到上一个极长+串,再进行判断。这样就变成 了。只要改动for循环中的一部分内容就好了:j=nxt[nxt[i]]; if(siz[j]>siz[nxt[i]] || siz[i]>siz[nxt[i]]){ siz[i]+=siz[j]+siz[nxt[i]]; link(i, nxt[j]); flag=1; if(pre[i]) i=pre[pre[i]]; } else i=j;接下来正解就水到渠成啦!!对于 的每一个极长段,我们可以对其分开讨论,这样就变成了若干个特殊性质的叠加。
需要注意的一点是,若对于 的某一个极长串, 在对应的位置的两边并不属于一个独立的极长串,就无法操作了。此时直接输出
No就好。于是,这道题就做完了。
Code
const int N=1e6+7; int n; char s[N], t[N]; namespace sub{ int n; char s[N], t[N]; int siz[N], pre[N], nxt[N], cnt; void link(int u,int v){ nxt[u]=v, pre[v]=u; } bool check(){ s[n+1]=t[n+1]='\0'; // cout<<s+1<<' '<<t+1<<endl; if(t[1]=='-'){ rep(i, 1, n) s[i]=s[i]=='-'?'+':'-'; } cnt=0; if(s[1]=='-') cnt=1, siz[1]=0; int tmp=1; rep(i, 2, n+1){ if(s[i]!=s[i-1]) siz[++cnt]=tmp, tmp=1; else ++tmp; } if(cnt%2==0) siz[++cnt]=0; rep(i, 1, cnt-1) link(i, i+1); nxt[cnt]=0; while(nxt[1]){ bool flag=0; for(int i=1, j; nxt[i];){ j=nxt[nxt[i]]; if(siz[j]>siz[nxt[i]] || siz[i]>siz[nxt[i]]){ siz[i]+=siz[j]+siz[nxt[i]]; link(i, nxt[j]); flag=1; if(pre[i]) i=pre[pre[i]]; } else i=j; } if(!flag) break; } return !nxt[1]; } } void run(){ cin>>s+1>>t+1; n=strlen(s+1); for(int i=1; i<=n;){ int pos=i; while(pos<=n && t[pos]==t[i]) ++pos; if(i!=1 && s[i]==s[i-1] || pos!=n+1 && s[pos]==s[pos-1]){ cout<<"No\n"; return; } sub::n=pos-i; rep(j, 1, pos-i) sub::s[j]=s[i+j-1], sub::t[j]=t[i+j-1]; if(!sub::check()){ cout<<"No\n"; return; } rep(j, i, pos-1) s[j]=t[j]; i=pos; } cout<<"Yes\n"; } signed main(){ ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int t; cin>>t; while(t--) run(); }都看到这里了,点个赞再走呗。
- 1
信息
- ID
- 10444
- 时间
- 2000ms
- 内存
- 512MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者