BZOJ4345 POI2016Korale(构造+堆+线段树)
注意到k与n同阶,考虑构造一种枚举子集的方式,使得尽量先枚举较小的子集。首先sort一下,用堆维护待选子集。每次取出最小子集,并加入:1.将子集中最大数ai替换为ai+1 2.直接向子集中添加ai+1 这两个子集(若不存在ai+1则不操作)。如此操作k次即可得到第一问的答案。
对于正确性,我们证明当删除一个子集后恰好比他大的下一个子集一定在堆中。采取归纳和反证。显然每个子集都可以由上面的构造方式变换得来。归纳基础显然。假设该子集和比它小的所有子集已被枚举,如果恰好比它大的这个子集不在堆里,则说明可以通过变换得到这个子集的子集均未被枚举,这些子集一定不大于当前子集,这与所有比它小的子集都已枚举矛盾。
下面构造方案。只需要算出需要找该总和下第几小的方案,按字典序暴力dfs就可以了,dfs时保证总和不超过第一问的答案即可保证复杂度,找编号最小的可被加入的物品可以用线段树。开始懵逼了半天线段树在这有什么用,然后突然醒悟字典序是读入的而不是排序之后的……没救了。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
#define N 1000010
#define ll long long
int n,m,id[N],b[N],cnt,tot;
int L[N<<],R[N<<],tree[N<<];
ll ans;
struct data
{
ll x;int i;
bool operator <(const data&a) const
{
return x>a.x;
}
}a[N];
priority_queue<data> q;
bool cmp(const data&a,const data&b)
{
return a.i<b.i;
}
void build(int k,int l,int r)
{
L[k]=l,R[k]=r;
if (l==r) {tree[k]=a[l].x;return;}
int mid=l+r>>;
build(k<<,l,mid);
build(k<<|,mid+,r);
tree[k]=min(tree[k<<],tree[k<<|]);
}
int qmin(int k,int l,int r)
{
if (L[k]==l&&R[k]==r) return tree[k];
int mid=L[k]+R[k]>>;
if (r<=mid) return qmin(k<<,l,r);
else if (l>mid) return qmin(k<<|,l,r);
else return min(qmin(k<<,l,mid),qmin(k<<|,mid+,r));
}
int query(int k,int p,ll x)
{
if (L[k]==R[k]) return L[k];
int mid=L[k]+R[k]>>;
if (p>mid) return query(k<<|,p,x);
else if (qmin(k<<,p,mid)<=x) return query(k<<,p,x);
else return query(k<<|,mid+,x);
}
void dfs(int k,ll s)
{
if (tot==) return;
if (s==ans) {tot--;if (tot==) for (int i=;i<=cnt;i++) printf("%d ",id[i]);return;}
int p=query(,k+,ans-s);
while (p<=n)
{
id[++cnt]=p;
dfs(p,s+b[p]);if (tot==) return;
cnt--;
p=query(,p+,ans-s);
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj4345.in","r",stdin);
freopen("bzoj4345.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
n=read(),m=read();
for (int i=;i<=n;i++) b[i]=a[i].x=read(),a[i].i=i;
a[n+].x=,a[n+].i=n+;build(,,n+);
sort(a+,a+n+);reverse(a+,a+n+);
q.push((data){a[].x,});
for (int i=;i<m;i++)
{
data x=q.top();q.pop();
if (x.x>ans) tot=;
ans=x.x;tot++;
if (x.i<n) q.push((data){x.x-a[x.i].x+a[x.i+].x,x.i+}),q.push((data){x.x+a[x.i+].x,x.i+});
}
cout<<ans<<endl;
dfs(,);
return ;
}
BZOJ4345 POI2016Korale(构造+堆+线段树)的更多相关文章
- BNUOJ-26475 Cookie Selection 堆,线段树等
题目链接:http://www.bnuoj.com/bnuoj/problem_show.php?pid=26475 题意:每次输入一个操作,如果是数字,那么放入一个容器中,如果是#号,取出当前容器中 ...
- 【BZOJ4919】[Lydsy六月月赛]大根堆 线段树合并
[BZOJ4919][Lydsy六月月赛]大根堆 Description 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切 ...
- 【AtCoder Regular Contest 080E】Young Maids [堆][线段树]
Young Maids Time Limit: 50 Sec Memory Limit: 512 MB Description 给定一个排列,每次选出相邻的两个放在队头,要求字典序最小. Input ...
- 【BZOJ4388】JOI2012 invitation 堆+线段树+并查集(模拟Prim)
[BZOJ4388]JOI2012 invitation Description 澳洲猴举办了一场宴会,他想要邀请A个男生和B个女生参加,这A个男生从1到A编号,女生也从1到B编号.现在澳洲猴知道n组 ...
- BZOJ4919[Lydsy1706月赛]大根堆-------------线段树进阶
是不是每做道线段树进阶都要写个题解..根本不会写 Description 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切 ...
- BZOJ.4919.[Lydsy1706月赛]大根堆(线段树合并/启发式合并)
题目链接 考虑树退化为链的情况,就是求一个最长(严格)上升子序列. 对于树,不同子树间是互不影响的.仿照序列上的LIS,对每个点x维护一个状态集合,即合并其子节点后的集合,然后用val[x]替换掉第一 ...
- 【CF1023D】Array Restoration(构造,线段树)
题意:有一个长为n的序列,对其进行q次操作,第i次操作可以把连续的一段覆盖为i 现在给出操作后的序列,第i个数字为a[i],其中有一些为0的位置可以为任意值,要求构造任意一组合法的操作后的序列 无解输 ...
- POJ 2991 Crane (线段树)
题目链接 Description ACM has bought a new crane (crane -- jeřáb) . The crane consists of n segments of v ...
- 重识线段树——Let's start with the start.
声明 本文为 Clouder 原创,在未经许可情况下请不要随意转载.原文链接 前言 一般地,这篇文章是给学习过线段树却仍不透彻者撰写的,因此在某些简单的操作上可能会一笔带过. 当然了,入门线段树后也可 ...
随机推荐
- shell 输出带颜色字体
输出特效格式控制:\033[0m 关闭所有属性 \033[1m 设置高亮度 \03[4m 下划线 \033[5m 闪烁 \033[7m 反显 \033[8m 消隐 \ ...
- 【shell脚本学习-4】
文本处理 #!/bin/bash#----------文本处理---------- #---------------echo----------------- # "-n":处理光 ...
- jQuery(二)事件
鼠标事件: click dblclick mouseenter:鼠标进入 mouseleave:鼠标离开 hover:鼠标悬停 <!DOCTYPE html> <html> & ...
- html 截图粘粘图片JS
web前端socket聊天室功能和在线编辑器上传编辑内容的时候经常会需要上传一些图文信息,但是很多编辑器不支持截图粘粘的功能,这里参考了网友分享的可用方法做一个记录. <html> < ...
- JDK8新垃圾回收机制--G1垃圾回收机制
G1全称是Garbage First Garbage Collector,使用G1的目的是简化性能优化的复杂性.例如,G1的主要输入参数是初始化和最大Java堆大小.最大GC中断时间. G1 GC由Y ...
- python 函数 练习
# 2.写函数,接收n个数字,求这些参数数字的和. def sum_func(*args): total = 0 for i in args: total += i return total prin ...
- Java学习笔记三:Java的变量、常量、变量的类型及使用规则
Java的变量.常量.变量的类型及使用规则 每一种语言都有一些具有特殊用途的词,Java也不例外,它们被称为关键字.关键字对 Java 的编译器有着特殊的意义. 一:Java中的关键字: 注:Java ...
- Leecode刷题之旅-C语言/python-26.删除数组中的重复项
/* * @lc app=leetcode.cn id=26 lang=c * * [26] 删除排序数组中的重复项 * * https://leetcode-cn.com/problems/remo ...
- Leecode刷题之旅-C语言/python-13.罗马数字转整数
/* * @lc app=leetcode.cn id=13 lang=c * * [13] 罗马数字转整数 * * https://leetcode-cn.com/problems/roman-to ...
- 通过SVI实现VLAN间通信
两个不同网段的计算机与三层交换机直连,通过SVI实现VLAN间通信vlan 1 //几个不同网段就创建几个VLANvlan 2 int f0/1 //划分VLANswitchport mode acc ...