CF1474-D. Cleaning

题意:

给出一个长度为\(n\)的正整数序列,你可以对序列进行如下操作:

  • 对序列中相邻的两个数字\(a_{i}, a_{i+1}\)同时减去一个数字\(t(t<=min(a_{i},a_{i+1}))\)。

现在你有一次机会可以将序列中任意两个相邻的数字交换位置(可以不交换)。问你可不可以通过上述操作将序列中所有数字都减为\(0\)。


题解:

在说具体做法之前,先考虑三个事情:

1. 先不考虑交换数字,在不交换数字的情况我们要把序列中全部的数字都消为\(0\)(当然也可能不能全部消为0)可以通过什么方法呢?可以通过以下两种操作获得:

首先我们假设在\(a_1\)的前面有一个\(a_0=0\),那么消除的过程就是\(a_1=a_1-a_0, a_2=a_2-a_1,..., a_n=a_n-a_{n-1}\),这样顺利的话就可以把全部的数字消掉。

或者我们假设在\(a_n\)的后面有一个\(a_{n+1}=0\),那么过程为\(a_n=a_n-a_{n+1}, a_{n-1}=a_{n-1}-a_n,..., a_1=a_1-a_2\),同样也可以把全部的数字都消掉。

上述操作为顺利情况下消除的过程,但实际上并不一直是那么的顺利。以上述的第一种操作为例,假如有\(a_{i-1}>a_{i}\),那么就会出现\(a_{i}<0\)的情况,这显然是不可能的,同样第二种操作也可能会出现这种情况。

2. 如果从前往后减,那么在交换了\(a_{i},a_{i-1}\)这两个数字之后会不会对\(a_{i-1}\)之前的数字造成影响呢?同样的从后往前减,交换\(a_{i},a_{i+1}\)之后会不会对\(a_{i+1}\)之后的数字造成影响呢?这两个问题的答案是否定的,均不会造成影响。

3. 对于一个序列,假设现在这个序列可以从前往后把所有数字都消掉,那么先从前往后消掉一部分,那么可不可以从后往前把剩下的一部分全部消掉呢?再假设这个序列不能从前往后或从后往前把全部数字消掉,那么能不能通过先从前往后消掉一部分再从后往前消掉另一部分把整个序列消掉?

换句话说,对于一个序列而言,先从前往后消去一部分,再从后往前消去另一部分,是否和只从前往后或只从后往前消除是等效的呢(能全部消掉或不能)?答案是肯定的,这也是本题的关键。


前面作了那么多铺垫,现在说一下做法。先定义两个数组\(pre(prefix)\)和\(suf(suffix)\),\(pre[i]\)表示从前往后消掉了\(a_{1}, a_{2},..., a_{i-1}\)之后\(a_{i}\)的值,\(suf[i]\)表示从后往前消掉了\(a_{n}, a_{n-1},...,a_{i+1}\)之后\(a[i]\)的值。这里说一下,不论是从前往后还是从后往前,如果\(a_{i}\)减完之后得到了一个负数,那么他之后的所有数字不论是正是负都没有意义了,所以\(a_{i}\)以及\(a_{i}\)之后所有数字就需要用一个特殊的标记这个\(pre\)或\(suf\)是无效的。

现在就可以枚举交换的数字了,比如现在要枚举的是交换\(a_{i}\)和\(a_{i+1}\),那么只需要看\(pre[i-1],a[i+1],a[i],suf[i+2]\)这几个数字构成的序列可不可以通过从前往后或者从后往前给全部消掉即可,如果可以答案就是\(YES\),后面也就不用继续枚举了;如果全部枚举之后都不能那么答案就是\(NO\)。当然这有个前提就是\(pre[i-1]\)和\(suf[i+2]\)不能是无效的,也就是不能是你之前打过特殊标记的。


AC代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector> void solve() {
int n;
scanf("%d", &n);
std::vector<int>a(n + 2);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
std::vector<int>pre(n + 2), suf(n + 2);
for (int i = 1; i <= n; i++) {
if (pre[i - 1] == -1 || a[i] < pre[i - 1]) {
pre[i] = -1;
} else {
pre[i] = a[i] - pre[i - 1];
}
}
if (pre[n] == 0) {
printf("YES\n");
return;
}
for (int i = n; i > 0; i--) {
if (suf[i + 1] == -1 || a[i] < suf[i + 1]) {
suf[i] = -1;
} else {
suf[i] = a[i] - suf[i + 1];
}
}
for (int i = 0; i <= n - 2; i++) {
int l = i, r = i + 3;
if (pre[l] == -1 || suf[r] == -1) {
continue;
}
if (a[r - 1] >= pre[l] && a[l + 1] >= suf[r] && a[r - 1] - pre[l] == a[l + 1] - suf[r]) {
printf("YES\n");
return;
}
}
printf("NO\n");
} int main() {
int T;
scanf("%d", &T);
while(T--) {
solve();
} return 0;
}

小结:

本题本质上就是暴力,只不过\(O(n^2)\)的暴力是不能接受的,所以先对原来数据进行预处理,使得最终时间复杂度从\(O(n^2)\)减为\(O(n)\)。

CF1474-D. Cleaning的更多相关文章

  1. 【bzoj1672】[USACO2005 Dec]Cleaning Shifts 清理牛棚

    题目描述 Farmer John's cows, pampered since birth, have reached new heights of fastidiousness. They now ...

  2. Coursera-Getting and Cleaning Data-week1-课程笔记

    博客总目录,记录学习R与数据分析的一切:http://www.cnblogs.com/weibaar/p/4507801.html -- Sunday, January 11, 2015 课程概述 G ...

  3. Coursera-Getting and Cleaning Data-Week2-课程笔记

    Coursera-Getting and Cleaning Data-Week2 Saturday, January 17, 2015 课程概述 week2主要是介绍从各个来源读取数据.包括MySql ...

  4. Coursera-Getting and Cleaning Data-Week3-dplyr+tidyr+lubridate的组合拳

    Coursera-Getting and Cleaning Data-Week3 Wednesday, February 04, 2015 好久不写笔记了,年底略忙.. Getting and Cle ...

  5. Coursera-Getting and Cleaning Data-week4-R语言中的正则表达式以及文本处理

    博客总目录:http://www.cnblogs.com/weibaar/p/4507801.html Thursday, January 29, 2015 补上第四周笔记,以及本次课程总结. 第四周 ...

  6. 【BZOJ1672】[Usaco2005 Dec]Cleaning Shifts 清理牛棚 动态规划

    [BZOJ1672][Usaco2005 Dec]Cleaning Shifts Description Farmer John's cows, pampered since birth, have ...

  7. poj 2376 Cleaning Shifts

    http://poj.org/problem?id=2376 Cleaning Shifts Time Limit: 1000MS   Memory Limit: 65536K Total Submi ...

  8. POJ 2376 Cleaning Shifts(轮班打扫)

    POJ 2376 Cleaning Shifts(轮班打扫) Time Limit: 1000MS   Memory Limit: 65536K [Description] [题目描述] Farmer ...

  9. POJ 2376 Cleaning Shifts 贪心

    Cleaning Shifts 题目连接: http://poj.org/problem?id=2376 Description Farmer John is assigning some of hi ...

  10. Bzoj 3389: [Usaco2004 Dec]Cleaning Shifts安排值班 最短路,神题

    3389: [Usaco2004 Dec]Cleaning Shifts安排值班 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 218  Solved: ...

随机推荐

  1. centos7+宝塔+ssrpanel v3 魔改版 前后端配置教程

    一.服务端 1.安装宝塔 登录 SSH 后,直接安装宝塔. yum install -y wget && wget -O install.sh http://download.bt.c ...

  2. JD6621快速充电协议芯片,带有PPS 控制器的USB-PD3.0

    描述 JD6621是高度集成的USB供电(PD)控制器,支持USB PD 3.0 ,该USB PD 3.0 具有针对USBType-C下游接口(源)设计的可编程电源(PPS)规范.它监视CC引脚以检测 ...

  3. STL_list容器

    一.List简介 链表是一种物理存储单元上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的. 链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成.每 ...

  4. Samba共享工具安装

    Samba 是一种在局域网上共享文件的一种通信协议,它为局域网内的不同计算机之间提供文件的共享服务. (1)下载并安装 Samba 工具. 确定 Ubuntu 已连接到互联网, 执行如下命令下载 Sa ...

  5. 从软件(Java/hotspot/Linux)到硬件(硬件架构)分析互斥操作的本质

    先上结论: 一切互斥操作的依赖是 自旋锁(spin_lock),互斥量(semaphore)等其他需要队列的实现均需要自选锁保证临界区互斥访问. 而自旋锁需要xcmpchg等类似的可提供CAS操作的硬 ...

  6. C++11中string与数值类型的转换

    C++中string与数值类型的相互转换记录 string转int.double.long string s = "123.456"; // string -> int co ...

  7. LoadRunner监控Centos和Ubuntu资源之服务器配置

    Centos 我用的版本是Centos6.8   首先更新源以及基础操作我就不说了,直接上步骤: Step 1 安装相关程序 执行命令:yum install inetd,这一步是为了安装rstatd ...

  8. jmeter---线程组执行顺序记录

    一.默认未勾选测试计划中独立运行每个线程组时,线程组并行执行,如下,设置三个请求,每个线程组设置5秒启动5个线程. 未勾选独立运行 运行结果如下,三个线程并行执行 勾选后,一个线程组执行完后才执行下一 ...

  9. Angular入门到精通系列教程(14)- Angular 编译打包 & Docker发布

    目录 1. 概要 2. 编译打包 2.1. 基本打包命令 2.2. 打包部署到二级目录 3. Angular站点的发布 3.1. web服务器发布 3.2. 使用docker发布 4. 总结 环境: ...

  10. (006)每日SQL学习:关于to_char函数

    to_char函数的官方文档说明: 详细to_char请移步:https://www.cnblogs.com/reborter/archive/2008/11/28/1343195.html 需求:n ...