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 的核心思 ... 
随机推荐
- 解决使用go get 下载模块下载超时的问题
			解决使用go get 下载模块下载超时的问题 解决使用go get 下载模块下载超时的问题 使用go env可以看到,默认的GOPROXY的值是https://proxy.golang.org, ... 
- Eclipse修改方法内容不用重启Jetty服务器
			我Eclipse以前DEBUG模式时,修改方法里的内容是不用重启的, 现在修改方法里是一行代码都要重启服务器了,很麻烦,速度慢了,找了百度,那些方法对我不合适,可能遇到的问题不一样. 也许会合适遇到和 ... 
- i.MX6UL: i.MX 6UltraLite处理器 - 低功耗,安全,Arm® Cortex®-A7内核
			i.MX6UL: i.MX 6UltraLite处理器 - 低功耗,安全,Arm Cortex-A7内核 概述 MX6UltraLite作为i.MX6系列的扩展,一系列高性能.超高效的处理器,采用先进 ... 
- HashMap底层实现原理及面试常见问题
			HashMap底层源码分析 1.HashMap底层采用的存储结构 1.在JDK1.7及之前采用的存储结构是数组+链表 2.到了JDK1.8之后采用的是数组+链表+红黑树 2.HashMap实现的原理 ... 
- Java swing JFrame用repaint出现闪烁的问题解决
			这几天用swing写登录页面背景动图的时候发现一直会有闪烁(我的类是继承JFrame),就来搜原因后发现好像是因为repaint会调用update()方法中的清屏操作导致闪烁. 我当时看的是这个文章 ... 
- 尚硅谷Java——宋红康笔记【day11-day18】
			day11 Eclipse中的快捷键: * 1.补全代码的声明:alt + / * 2.快速修复: ctrl + 1 * 3.批量导包:ctrl + shift + o * 4.使用单行注释:ctrl ... 
- 【题解】【洛谷 P1967】 货车运输
			目录 洛谷 P1967 货车运输 原题 题解 思路 代码 洛谷 P1967 货车运输 原题 题面请查看洛谷 P1967 货车运输. 题解 思路 根据题面,假设我们有一个普通的图: 作图工具:Graph ... 
- apache jmeter下载与安装
			JMeter是Apache软件基金会的产品,用于对静态的和动态的资源性能进行测试.jmeter可以运行在多个平台上,如Windows和Linux,本文讲的是在Windows安装jmeter. 工具/原 ... 
- 618技术特辑(三)直播带货王,“OMG买它”的背后,为什么是一连串技术挑战?
			[本期推荐]为什么一到大促,我们的钱包总是被掏空?是大家自制力不够,还是电商平台太会读懂人心,从技术维度,抽丝剥茧一探究竟. 摘要:动辄几十上百万人同时在线的直播间,让所有人能同时公平的去抢购,并且还 ... 
- SQL 利用存储过程实现对表数据有则更新无则添加(转)
			初学存储过程,发现这篇文章简单易懂,特意转载,地址 http://blog.csdn.net/luotuomianyang/article/details/52013144 如果某一操作包含大量的T- ... 
