[CF1031E]Triple Flips
题目大意:给你一个长度为$n$的$01$串,一次操作定义为:选取$3$个等距的元素,使其$0$变$1$,$1$变$0$,要求在$\Big\lfloor \dfrac n 3\Big\rfloor+12$次操作内变为全$0$。输出是否可行以及方案
题解:skip1978的博客讲的十分详细。发现给的操作次数很少,基本上一次操作要使得$3$个元素变成$0$
对于区间$[l,r]$,若$a_l=0$,这一位不用翻转,缩小到区间$[l+1,r]$,这样$a_l,a_{l+1},a_{l+2}$有$4$中可能:
- $1,1,1:$翻转$a_l,a_{l+1},a_{l+2}$就可以使得这三位变$0$
- $1,0,1:$翻转$a_l,a_{l+2},a_{l+4}$就可以使得这三位变$0$
- $1,0,0:$翻转$a_l,a_{l+3},a_{l+6}$就可以使得这三位变$0$
- $1,1,0:$可以按相同方法收缩右端点,直到右端点也出现这样的情况
- 若$l,r$奇偶性相同,可以翻转$a_l,a_{\frac{l+r}{2}},a_r$和$a_{l+1},a_{\frac{l+r}{2}},a_{r-1}$使得这六位变成$0$
- 若$l,r$奇偶性不同,可以翻转$a_l,a_{\frac{l+r-1}{2}},a_{r-1}$和$a_{l+1},a_{\frac{l+r+1}{2}},a_r$使得这六位变成$0$
然后发现若区间长度大于等于$8$,一定可以翻转成$0$,并且所有合法的翻转只有$12$次,可以暴力枚举每一个操作是否使用即可
卡点:找到答案后忘记退出
C++ Code:
#include <cstdio>
#include <vector>
#define maxn 100010 int n, s[maxn];
struct Step {
int a, b, c;
inline Step() {}
inline Step(int __a, int __b, int __c) {a = __a, b = __b, c = __c;}
};
std::vector<Step> Ans;
bool find_ans = false; inline void reverse(int a, int b, int c) {
s[a] ^= 1, s[b] ^= 1, s[c] ^= 1;
Ans.push_back(Step(a, b, c));
}
inline void reverse(int a, int c) {
int b = a + c >> 1;
reverse(a, b, c);
} std::vector<std::pair<int, int> > V;
int tmp[maxn];
#define rev(x) tmp[x.first] ^= 1, tmp[x.first + x.second >> 1] ^= 1, tmp[x.second] ^= 1
inline bool end(int l, int r) {
for (int i = l; i <= r; i++) if (tmp[i]) return false;
return true;
}
void calc(int l, int r) {
for (int i = l; i <= r - 2; i++) {
for (int j = i + 2; j <= r; j += 2) {
V.push_back(std::make_pair(i, j));
}
}
int sz = V.size(), U = 1 << sz;
for (int i = 0; i < U; i++) {
for (int i = l; i <= r; i++) tmp[i] = s[i];
for (int j = 0; j < sz; j++) if (i & 1 << j) rev(V[j]);
if (end(l, r)) {
find_ans = true;
for (int j = 0; j < sz; j++) if (i & 1 << j) reverse(V[j].first, V[j].second);
return ;
}
}
} #define checkl(x, a, b, c) (s[x] == a && s[x + 1] == b && s[x + 2] == c)
#define work(l, r, L, R) {reverse(l, r), solve(L, R); return ;}
#define checkr(x, a, b, c) (s[x] == a && s[x - 1] == b && s[x - 2] == c)
void solve(int l, int r) {
if (r - l + 1 <= 8) {
while (r - l + 1 < 8 && l > 1) l--;
while (r - l + 1 < 8 && r < n) r++;
calc(l, r);
return ;
}
if (!s[l]) {solve(l + 1, r); return ;}
if (!s[r]) {solve(l, r - 1); return ;}
if (checkl(l, 1, 1, 1)) work(l, l + 2, l + 3, r);
if (checkl(l, 1, 0, 1)) work(l, l + 4, l + 3, r);
if (checkl(l, 1, 0, 0)) work(l, l + 6, l + 3, r);
if (checkr(r, 1, 1, 1)) work(r - 2, r, l, r - 3);
if (checkr(r, 1, 0, 1)) work(r - 4, r, l, r - 3);
if (checkr(r, 1, 0, 0)) work(r - 6, r, l, r - 3);
if (r - l & 1) {
reverse(l, r - 1), reverse(l + 1, r);
solve(l + 3, r - 3);
} else {
reverse(l, r), reverse(l + 1, r - 1);
solve(l + 3, r - 3);
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", s + i);
solve(1, n);
if (find_ans) {
puts("YES");
printf("%d\n", Ans.size());
for (std::vector<Step>::iterator it = Ans.begin(); it != Ans.end(); it++) {
printf("%d %d %d\n", it -> a, it -> b, it -> c);
}
} else puts("NO");
return 0;
}
[CF1031E]Triple Flips的更多相关文章
- Codeforces 1071 C - Triple Flips
C - Triple Flips 思路: 小范围暴力 大范围递归构造 构造方法: solve(l, r) 表示使l 到 r 区间全变为0的方法 为了使反转次数小于等于n/3 + 12 我们只需要保证每 ...
- Codeforces1071C Triple Flips 【构造】【Four Russians】
题目分析: 这种题目显然可以先考虑哪些无解.我们发现我们不考虑操作次数的时候,我们可以选择连续的三个进行异或操作. 这样我们总能使得一个序列转化为$000...000xy$的形式.换句话说,对于$00 ...
- Codeforces 1071C Triple Flips 构造
原文链接 https://www.cnblogs.com/zhouzhendong/p/CF1071C.html 题目传送门 - CF1071C 题意 给定一个长度为 n 的 01 数列,限定你在 $ ...
- Technocup 2019 - Elimination Round 2
http://codeforces.com/contest/1031 (如果感觉一道题对于自己是有难度的,不要后退,懂0%的时候敲一遍,边敲边想,懂30%的时候敲一遍,边敲边想,懂60%的时候敲一遍, ...
- Codeforces Round #517
传送门 A. Cram Time 你有一本书,阅读第\(i\)页需要花费\(i\)的时间.你第一天有\(a\)的时间,第二天有\(b\)的时间,问你的总阅读页数的最大值. Input: 一行包含\(2 ...
- 山东省第七届ACM省赛------Triple Nim
Triple Nim Time Limit: 2000MS Memory limit: 65536K 题目描述 Alice and Bob are always playing all kinds o ...
- hdu 3908 Triple(组合计数、容斥原理)
Triple Time Limit: 5000/3000 MS (Java/Others) Memory Limit: 125536/65536 K (Java/Others) Total Su ...
- Flips测试类(page43)
测试用例:所用java类: StdOut,StdIn , Counter, StdRandom, public class Flips { public static void main(String ...
- hdu 5517 Triple(二维树状数组)
Triple Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Sub ...
随机推荐
- ASP.NET Web用户控件
用户控件可用来实现页面中可重用的代码,是可以一次编写就多处方便使用的功能块.它们是 ASP.NET控件封装最简单的形式.由于它们最简单,因此创建和使用它们也是最简单的.用户控件实际上是把已有的服务器控 ...
- php 移动或重命名文件(图片)到另一目录下的方法有多种,这里只列出三种:
php 移动或重命名文件(图片)到另一目录下的方法有多种,这里只列出三种: 方法一:使用copy函数 格式:copy(source,destination) 将文件从 source ...
- Symfony FOSUserBundle用户登录验证
symfony是一个由组件构成的框架,登录验证的也是由一些组件构成,下面就介绍一下FOSUserBundle的使用. 以symfony 3.3为例, 首先我们需要先安装一下FOSUserBundle. ...
- for循环小练习
for循环是前测试循环语句 for(初始值:判定条件:步长){ 循环语句 } For循环原理: For循环第一次执行:首先执行语句1,然后执行语句2,如果条件为真,向内执行执行循环语句3. 如果条件为 ...
- 06 python操作MySQL和redis(进阶)
python操作mysql.redis 阶段一.mysql事务 主要用于处理操作量大,复杂度高的数据.比如说,在人员管理系统中,你删除一个人员,你即需要删除人员的基本资料,也要删除和该人员相关的信息, ...
- u-boot.bin生成过程分析
ELF格式“u-boot”文件的生成规则如下,下面对应Makefile的执行过程分别分析各个依赖. $(obj)u-boot: depend version $(SUBDIRS) $(OBJS) $( ...
- HyperLedger Fabric 1.4 超级账本起源(5.1)
至比特币开源以来,无数技术人员对其进行研究,并且对该系统经过了无数次改进,超级账本项目(Hyperledger)最初也是用来改善比特币的底层技术,最终由Linux基金会组织发展起来. 开放 ...
- Git的使用规范(一)
1.建议使用 git add.2.不建议使用git commit -a3.撤销没有add的git checkout . 这个命令我们可以好好的介绍一下,如果当你对文件进行了修改,你没有进行git ad ...
- jquery validation remote进行唯一性验证时只使用自定义参数,不使用默认参数
在使用validation进行唯一性验证时,想各个模块写一个统一的方法,相统一参数名称,但是remote方法会默认把对应的参数传过去 如: 会把role.roleName默认作为变量提交过去 所以想自 ...
- Git中从远程的分支获取最新的版本到本地——两种命令
Git中从远程的分支获取最新的版本到本地有这样2个命令: 1. git fetch:相当于是从远程获取最新版本到本地,不会自动merge Git fetch origin master git log ...