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 的核心思 ...
随机推荐
- OFRecord 数据集加载
OFRecord 数据集加载 在数据输入一文中知道了使用 DataLoader 及相关算子加载数据,往往效率更高,并且学习了如何使用 DataLoader 及相关算子. 在 OFrecord 数据格式 ...
- YOLOV4知识点分析(一)
YOLOV4知识点分析(一) 简 介 yolov4论文:YOLOv4: Optimal Speed and Accuracy of Object Detection arxiv:https://arx ...
- Ucore lab1实验报告
练习一 Makefile 1.1 OS镜像文件ucore.img 是如何一步步生成的? + cc kern/init/init.c + cc kern/libs/readline.c + cc ker ...
- 【NX二次开发】Block UI 双精度
属性说明 常规 类型 描述 BlockID String 控件ID Enable Logical 是否可操作 Group Logical ...
- JavaScript 中的 Var,Let 和 Const 有什么区别
一.var 在ES5中,顶层对象的属性和全局变量是等价的,用var声明的变量既是全局变量,也是顶层变量 注意:顶层对象,在浏览器环境指的是window对象,在 Node 指的是global对象 var ...
- js 统计图插件chart.js
chart是一个纯js插件,它功能强大小巧使用也很简单. 第一步引入 chart.js . <script type="text/javascript" src=" ...
- Perm 排列计数
题目描述 称一个1,2,...,N的排列P1,P2...,Pn是Magic的,当且仅当2<=i<=N时,Pi>Pi/2. 计算1,2,...N的排列中有多少是Magic的,答案可能很 ...
- 深入理解 sync.Once 与 sync.Pool
深入理解 sync.Once 与 sync.Pool sync.Once 代表在这个对象下在这个示例下多次执行能保证只会执行一次操作. var once sync.Once for i:=0; i & ...
- Arduino参考手册-函数和变量及电路图
标题: Arduino参考手册-函数和变量及电路图 作者: 梦幻之心星 sky-seeker@qq.com 标签: [#Arduino,#参考手册,#函数,#变量] 目录: [Arduino] 日期: ...
- JS里的异步实例化
JS里的异步构造函数 众所周知,Js的构造函数是不能加上async/await来实现异步实例化的,一般当需要一个对象的属性是异步的结果时可以这样写: //! 一个需要指定时间后返回的异步函数 func ...