CF1458D Flip and Reverse[题解]
Flip and Reverse
题目大意
给定一个 \(01\) 字符串,有机会进行若干次操作,对于每一次操作:
选择该字符串的子串,要求是该子串内包含数量相同的 \(0\) , \(1\) 字符。
将该子串内的所有字符取反, \(1\) 变成 \(0\) ,\(0\) 变成 \(1\) 。
把选中的子串顺序反转。
求经过若干次操作后字典序最小的字符串。
分析
若将 \(1\) 赋值为 \(1\) , \(0\) 赋值为 \(-1\) ,进行前缀和运算,我们能够发现该操作的含义在前缀和中就是选择前缀和相同的两个点,将这两个点之间的前缀和反转。
例如样例 \(100101\) ,前缀和为 \(0\) , \(1\) , \(0\) , \(-1\) , \(0\) , \(-1\) , \(0\) 。
若我们选择前四个字符 \(1001\) 操作,等价于将七个前缀和中第 \(1\) 到第 \(5\) 个前缀和顺序反转,最后得到的结果都会是 \(011001\)。
通过前缀和图像我们能够较为轻松的发现这个性质:

红色的线表示对称轴,绿色的线便是操作之后的前缀和,略作分析能够发现其正确性。
考虑如何求得答案,考虑贪心。我们没有必要一位一位的去操作,我们只需要考虑每一位的前缀和最小能够填几就可以了。简单的,如果目前位数的前缀和为 \(k\) ,那么下一位的前缀和有两种可能 \(k+1\) , \(k-1\) ,我们当然想填 \(k-1\) ,考虑填入 \(k-1\) 的限制条件。
考虑对于原前缀和序列,每个数向相邻的数连无向边。由于对于前缀和序列的操作是选择子串翻转,并且开头和结尾的前缀和是一样的,那么其实不难发现,不管怎么操作,两个前缀和之间边的数量是不变的。
这样连边之后,能够填入 \(k-1\) 的有两种,第一种是没有连接 \(k+1\) 的边了,那么肯定就能够走 \(k-1\) ,第二种是 \(k\) 和 \(k-1\) 的连边至少有两条。
接下来说明为什么 \(k\) 和 \(k-1\) 的连边为什么至少需要两条。
如果 \(k\) 和 \(k-1\) 的连边只有一条,如果 \(k\) 后面直接就跟 \(k-1\) ,那么这种情况是肯定可以填的,但是由于我们已经知道了 \(k-1\) 和 \(k\) 的连边只有一条,所以最后不管怎么变化,前缀和不可能再回到 \(k\) ,自然也不会存在 \(k\) 与 \(k+1\) 的连边,则其实第一种情况就已经特判掉了只有一条连边时的情况。
那么 \(k\) 和 \(k-1\) 的连边有两条为什么一定对呢?首先后面原本就是 \(k-1\) 的情况当然是可以的,但是如果后面是 \(k+1\) ,要满足至少有两条与 \(k-1\)的连边,则必须满足如下图的前缀和变化:
而排除掉第一种特殊情况,若只有一条连边的情况则如下图:
发现限制条件后,就可以贪心的往下填,最后求出的答案即是最优解。
CODE
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int n;
char s[N];
int a[N],pre[N];
//edge[0/1][0/1][i]中第一位表示增减连边,第二位表示目前数值i的正负
int edge[2][2][N];
inline int read()
{
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
int main()
{
n=read();
while(n--){
scanf("\n%s",s+1);
int len=strlen(s+1);
for(register int i=1;i<=len;i++) a[i]=s[i]-'0';
for(register int i=1;i<=len;i++){ //处理前缀和
if(a[i]==1) pre[i]=pre[i-1]+1;
else pre[i]=pre[i-1]-1;
}
for(register int i=0;i<len;i++){ //处理出前缀和与边的数量f
int sym1= pre[i]>=0 ? 1 : 0,sym2= pre[i+1]>=0 ? 1 : 0;
int change= pre[i+1]>pre[i] ? 1 : 0;
edge[change][sym1][abs(pre[i])]++,edge[change^1][sym2][abs(pre[i+1])]++;
}
int now=0;
for(register int i=1;i<=len;i++){ //考虑每一位如何填充
int sym1= now>=0 ? 1 : 0;
if(edge[0][sym1][abs(now)]>=2||!edge[1][sym1][abs(now)]){
printf("0"),now--;
int sym2= now>=0 ? 1 : 0;
edge[0][sym1][abs(now+1)]--,edge[1][sym2][abs(now)]--;
}
else{
printf("1"),now++;
int sym2= now>=0 ? 1 : 0;
edge[1][sym1][abs(now-1)]--,edge[0][sym2][abs(now)]--;
}
}
printf("\n");
}
return 0;
}
CF1458D Flip and Reverse[题解]的更多相关文章
- [cf1458D]Flip and Reverse
将$s$中的01分别变为$1,-1$,即得到一个序列$a_{i}$(设其长度为$n$,下标范围为$[1,n]$) 对$a_{i}$建立一张有向图,其点集合为$Z$,并对$\forall 0\le k& ...
- 多校联训 DS 专题
CF1039D You Are Given a Tree 容易发现,当 \(k\) 不断增大时,答案不断减小,且 \(k\) 的答案不超过 \(\lfloor\frac {n}{k}\rfloor\) ...
- 小白学jquery Mobile《构建跨平台APP:jQuery Mobile移动应用实战》连载四(场景切换)
作为一款真正有使用价值的应用,首先应该至少有两个页面,通过页面的切换来实现更多的交互.比如手机人人网,打开以后先是进入登录页面,登录后会有新鲜事,然后拉开左边的面板,能看到相册.悄悄话.应用之类的其他 ...
- bzoj 2631: tree 动态树+常数优化
2631: tree Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 1716 Solved: 576[Submit][Status] Descrip ...
- 白学jquery Mobile《构建跨平台APP:jQuery Mobile移动应用实战》串行4(场景变化)
作为一个真正的利用价格值应用,首先,你应该至少有两页,通过切换页面来实现很多其他互动.比如手机人人网,首先,打开后进入登录页面,将有登录后,新的东西.然后拉左侧面板.你可以看到相册.私人信息.像其他应 ...
- css3 翻牌动画
最近做了一个特效,css是从网上找的,地址是这个: CSS3 animate flip下的纸牌翻转效果实例页面 把其中核心的css代码扒出来如下: /* The properties in this ...
- MOG插件(葡萄牙语,略作翻译)
这次记录下MOG大神的插件,自从我发现了这个插件,似乎开启了一个新世界诶~~~ 网址 https://atelierrgss.wordpress.com 1. MOG_YuruYuri.js CARA ...
- WebApp之H5登录注册
代码indexhtml <!DOCTYPE html> <html> <head> <meta charset="utf-8"> & ...
- 平衡树 & LCT
1. 非旋 Treap(FHQ Treap) 1.1. 算法简介 FHQ Treap 的功能非常强大.它涵盖了 Treap 几乎所有的功能 所以我非常后悔学了 Treap,浪费时间. FHQ 的核心思 ...
随机推荐
- 十二、.net core(.NET 6)添加通用的访问webapi的方法(包括HttpClient和HttpWebRequest)
开发通用的访问webapi方法. 在common工具文件夹下,新建一个类库项目:Wsk.Core.WebHelper,并引用Package包项目,然后新建一个类HttpClientHelper,用于使 ...
- [leetcode] 38. 报数(Java)(字符串处理)
38. 报数 水题 class Solution { public String next(String num) { String ans = ""; int i = 0; wh ...
- Go语言协程并发---生产者消费者实例
package main import ( "fmt" "strconv" "time" ) /* 改进生产者消费者模型 ·生产者每秒生产一 ...
- Python分析离散心率信号(中)
Python分析离散心率信号(中) 一些理论和背景 心率信号不仅包含有关心脏的信息,还包含有关呼吸,短期血压调节,体温调节和荷尔蒙血压调节(长期)的信息.也(尽管不总是始终如一)与精神努力相关联,这并 ...
- Windows下Django的安装与项目创建
1.Django的安装命令:pip install django 2.如果要指定安装版本可用:pip install django==1.10.3 3.查看指定的安装库:pip show django ...
- Java IO学习笔记六:NIO到多路复用
作者:Grey 原文地址:Java IO学习笔记六:NIO到多路复用 虽然NIO性能上比BIO要好,参考:Java IO学习笔记五:BIO到NIO 但是NIO也有问题,NIO服务端的示例代码中往往会包 ...
- Boost 矩形布尔运算
本文主要介绍boost库中矩形布尔运算的思路和代码解析.在此感谢Intel对开源事业的贡献. 基本概念 图形的插入 所有的操作的第一步都是进行图形的插入,我们需要声明定义好我们要使用的图形类型,以矩形 ...
- Java JDK 动态代理(AOP)使用及实现原理分析
一.什么是代理? 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理. 代理模式U ...
- Waymo object detect 2D解决方案论文拓展
FixMatch 半监督中的基础论文,自监督和模型一致性的代表作. Consistency regularization: 无监督学习的方式,数据\(A\)和经过数据增强的\(A\)计做\(A'\) ...
- NOIP模拟测试24「star way to hevaen·lost my music」
star way to heaven 题解 大致尝试了一下并查集,记忆化搜索,最小生成树 最小生成树是正解,跑最小生成树然后找到最大的值 欧几里德距离最小生成树学习 prim楞跑 至于为什么跑最小生成 ...