Description

有n种颜色的砖块,第i种颜色的砖块有a[i]个,你需要把他们放成一排,使得相邻两个砖块的颜色不相同,限定第一个砖块的颜色是start,最后一个砖块的颜色是end,请构造出一种合法的方案或判断无解。

HINT

【数据范围】

n,m≤1000000,1≤start,end≤n

∑ai<=1000000

Solution

全网唯一 一篇O(n)题解+bzoj最优解

这个题看大家都是优先队列,然后直接贪心放置。

还有用权值线段树来模拟堆过的%%%。

其实不用带logn也可以过的。

大家的方法是从左往右扫过去的。

对于这种插空排序的问题,还有一种考虑方法就是每个种类每个种类来考虑。

好处是,前面放过的种类放完了,和当前第i种永远不会产生冲突。

这就是我的大方向思路。

一、先不考虑端点固定的情况。

其实,不一定要先放最多的。

顺序可以随便。

假设放到完了前i种,那么,一共有sum[i]个。

对于后面的n-i种来说,前i种的方法对后面没有影响。

所以,肯定前i种放法中,选择相邻的情况最少的方案咯!

怎样凑出这个方案?

放完了前i种,设还剩下k个相邻位置。

1.对于第i种,肯定先插那k个位置中。这样每次相邻的-1,已经最优。

2.如果i种还剩下,那就从前面开始插空(不能和1中放的相邻)。这样相邻的数量不增不减。已经最优。

3.如果还剩下,那没有办法了。为了之后好处理,我们都把这些剩下的都放在末尾。

这样,不管你是数量较多的,还是数量较少的,

较多的,可以放在一起,由后面的再插空隔开。

较少的,就隔开之前相邻的。

至于怎么插空?

用一个最普通的链表就可以维护。

当然,我们每次要维护3中,开始连续的那一串的起始位置。方便下次直接访问。

二、有固定点呢?

两个端点比较麻烦。

所以我们就先放端点好了。

放的方法和上面差不多。

先放p,再放q

如果p的数量大于等于q。

那么放q的时候,直接插空,然后无论如何留下一个放末尾。

如果p的数量小于q。

那么放q的时候,插完空,直接往后放完即可。

(注意的是,这样的话有一个情况,就是在最后一个和倒数第二个之间还要插一个,后面放的时候特判一下)

然后放剩下k-2种。

按照刚才的策略即可。注意不能放在1前面,以及最后一个后面。

由于策略一直是最优的。

所以放完了之后,还有相邻元素,那就无解了。

三、一些细节

1.可能有两个端点颜色相同的情况。特判即可。bzoj上还有端点相同,且这个颜色只有一个的数据。。。。

2.刚才“二”中说的那个注意事项。

3.乱七八糟的各种边界情况和+1-1等等。

画个示意图就好理解了。

代码:

全程链表,所以复杂度线性。

(其实应该还有很多常数优化空间2333)

(这个题输入输出优化都很有用,输出优化快了400ms???)

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<iostream>
#define reg register int
#define il inline
#define numb (ch^'0')
using namespace std;
typedef long long ll;
const int N=+;
int nxt[N],id[N];//nxt后继,id颜色编号
int tot;
int k,p,q;
int a[N];
il void rd(int &x){
char ch;x=;
while(!isdigit(ch=getchar()));
for(x=numb;isdigit(ch=getchar());x=x*+numb);
}
il void prin(int x){
if(x/) prin(x/);
putchar(x%+'');
}
il void upda(int o,int to,int d){//初始化链表元素
nxt[o]=to;id[o]=d;
}
int main(){
rd(k);rd(p);rd(q);
for(reg i=;i<=k;++i)rd(a[i]);
if(p==q&&a[p]==){//特判一个点
if(k>) printf("");
else printf("%d",p);
return ;
}
int las=;
for(reg i=;i<=a[p];++i){//放p
upda(++tot,,p);
if(las) nxt[las]=tot;las=tot;
}
las=;
int pos=;//pos是每一次最后的连续一部分同种相邻颜色的起始位置
if(p!=q){//放q
int i;
for(i=;i<=a[q]-&&las<=a[p];++i){
upda(++tot,nxt[las],q);
nxt[las]=tot;++las;
}
if(a[p]>=a[q]){
nxt[a[p]]=++tot;
upda(tot,,q);
pos=a[q];
}
else{
pos=tot;
while(i<=a[q]){
nxt[tot]=tot+;
upda(++tot,,q);
++i;
}
}
}
else{
pos=;
}
int nd=tot;//末尾的编号
for(reg i=;i<=k;++i){//放其他的
if(i==p||i==q) continue;
int tmp=a[i];
while(a[i]&&nxt[pos]!=nd){//插后面的空
upda(++tot,nxt[pos],i);
nxt[pos]=tot;
a[i]--;++pos;
}
if(a[i]&&nxt[pos]==nd&&id[pos]==q){//细节2
upda(++tot,nxt[pos],i);
nxt[pos]=tot;
pos=tot;//warning!!!
a[i]--;
}
if(a[i]){//从前面插空
int now=;//start from a[p]
while(a[i]&&id[nxt[now]]!=i&&nxt[now]!=nd){
upda(++tot,nxt[now],i);
int to=nxt[now];
nxt[now]=tot;
now=to;
a[i]--;
}
if(a[i]){//如果还有剩余
int las=pos;
if(id[pos]!=i) pos=tot+;//warning!!! tot+1
while(a[i]){
upda(++tot,nxt[las],i);
nxt[las]=tot;
las=tot;
a[i]--;
}
}
}
}
for(reg i=;i!=nd;i=nxt[i]){//判断不合法
if(id[i]==id[nxt[i]]){
printf("");return ;
}
}
for(reg i=;i!=nd;i=nxt[i]){
prin(id[i]);putchar(' ');
}prin(id[nd]);
return ;
}

总结:

注意处理排序插空问题的两个大方法:

1.从左到右扫描。期间往往用数据结构维护。

2.分类别,同一个类别一起考虑。往往用到对插入的物品排序(当然本题不用)

[BZOJ3523][Poi2014]KLO-Bricks——全网唯一 一篇O(n)题解+bzoj最优解的更多相关文章

  1. [SDOI2009]Bill的挑战——全网唯一 一篇容斥题解

    全网唯一一篇容斥题解 Description Solution 看到这个题,大部分人想的是状压dp 但是我是个蒟蒻没想到,就用容斥切掉了. 并且复杂度比一般状压低, (其实这个容斥的算法,提出来源于y ...

  2. [JSOI2008]Blue Mary的战役地图——全网唯一一篇dp题解

    全网唯一一篇dp题解 网上貌似全部都是哈希+二分(反正我是大概baidu了翻了翻)(还有人暴力AC了的..) 哈希还是相对于dp还是比较麻烦的. 而且正确性还有可能被卡(当然这个题不会) 而且还容易写 ...

  3. BZOJ3523 [Poi2014]Bricks 【贪心】

    题目链接 BZOJ3523 题解 简单的贪心题 优先与上一个不一样且数量最多的,如果有多个相同,则优先选择非结尾颜色 比较显然,但不知怎么证 #include<algorithm> #in ...

  4. BZOJ3523[Poi2014]Bricks——贪心+堆

    题目描述 有n种颜色的砖块,第i种颜色的砖块有a[i]个,你需要把他们放成一排,使得相邻两个砖块的颜色不相同,限定第一个砖块的颜色是start,最后一个砖块的颜色是end,请构造出一种合法的方案或判断 ...

  5. scrapy-redis+selenium+webdriver解决动态代理ip和user-agent的问题(全网唯一完整代码解决方案)

    问题描述:在爬取一些反爬机制做的比较好的网站时,经常会遇见一个问题就网站代码是通过js写的,这种就无法直接使用一般的爬虫工具爬取,这种情况一般有两种解决方案 第一种:把js代码转为html代码,然后再 ...

  6. 全网唯一正常能用的centos7 安装mysql5.7.35 22 33 25

    CentOS7.4用yum安装并配置MySQL5.7   1.配置YUM源 下载MySQL源安装包 wget http://dev.mysql.com/get/mysql57-community-re ...

  7. (分享)视频压缩Free Video Compressor 汉化版/中文版【全网唯一】

    介绍:Free Video Compressor 是一个免费视频压缩软件,可以帮您有效的压缩视频.电影文件的体积大小,减小占用的磁盘空间,使之更容易放到手机中保存播放Free Video Compre ...

  8. 全网唯一的纯前端实现的canvas支持多图压缩并打包下载的工具

    技术栈: canvas jszip.js(网页端压缩解压缩插件JSZIP库) FileSaver.js(文件保存到本地库) 直接解读源码: <div class="cont" ...

  9. 【微信小程序】mpvue中页面之间传值(全网唯一真正可行的方法,中指推了一下隐形眼镜)

    摘要: mpvue中页面之间传值(注意:是页面之间,不是组件之间) 场景:A页面跳转B页面,在B页面选择商品,将商品名带回A页面并显示 使用api: getCurrentPages step1: A页 ...

随机推荐

  1. Qt-QSplashScreen-程序启动动画

    多数大型应用程序启动时可会在程序完全启动前显示一个启动画面,在程序完全启动后消失,程序启动画面可以显示相关产品的一些信息,使用户在等待程序启动时同时了解产品的相关功能,这也是一种宣传方式. 首先运行界 ...

  2. .NET邮件发送详情

    ①百度下载个Free Smtp Server ②下载完成后,打开进去,点击左上角的options,弹出窗口,进行如下图选项即可(一般默认已正确选中),然后我们可以把这软件关了. (下次你重启电脑时,也 ...

  3. Python汉诺塔问题递归算法与程序

    汉诺塔问题: 问题来源:汉诺塔来源于印度传说的一个故事,上帝创造世界时作了三根金刚石柱子,在一根柱子上从上往下从小到大顺序摞着64片黄金圆盘.上帝命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱 ...

  4. 深入理解java虚拟机学习笔记(二)

    第三章 垃圾收集器与内存分配策略 概述 ​ 程序计数器.虚拟机栈.本地方法栈3个区随线程而生,随线程而灭.因此大体上可认为这几个区域的内存分配和回收都具备确定性.在方法/线程结束时,内存自然就跟着回收 ...

  5. selenium常用操作方法

    Webdriver中比较常用的操作元素的方法: clear() 清除输入框的默认内容 send_keys("xxx") 在一个输入框里输入xx内容 ——如果输入中文,则需要在脚本开 ...

  6. LogisticRegression Algorithm——机器学习(西瓜书)读书笔记

    import numpy as np from sklearn.datasets import load_breast_cancer import sklearn.linear_model from ...

  7. js经典试题之原型与继承

    js经典试题之原型与继承 1:以下代码中hasOwnProperty的作用是? var obj={} …….. obj.hasOwnProperty("val") 答案:判断obj ...

  8. Python中的__future__

    在Python中,你如果在某一个版本的Python想使用未来版本中的功能,可以使用如下语法实现: from __future__ import futurename 这条语句必须放在module文件的 ...

  9. 自测之Lesson8:进程操作

    题目:请解释wait是如何同步父子进程的. 程序代码: #include <stdio.h> #include <unistd.h> #include <sys/type ...

  10. Thunder团队第五周 - Scrum会议6

    Scrum会议6 小组名称:Thunder 项目名称:i阅app Scrum Master:邹双黛 工作照片: 宋雨同学在拍照,所以不在照片内. 参会成员: 王航:http://www.cnblogs ...