注意到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(构造+堆+线段树)的更多相关文章

  1. BNUOJ-26475 Cookie Selection 堆,线段树等

    题目链接:http://www.bnuoj.com/bnuoj/problem_show.php?pid=26475 题意:每次输入一个操作,如果是数字,那么放入一个容器中,如果是#号,取出当前容器中 ...

  2. 【BZOJ4919】[Lydsy六月月赛]大根堆 线段树合并

    [BZOJ4919][Lydsy六月月赛]大根堆 Description 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切 ...

  3. 【AtCoder Regular Contest 080E】Young Maids [堆][线段树]

    Young Maids Time Limit: 50 Sec  Memory Limit: 512 MB Description 给定一个排列,每次选出相邻的两个放在队头,要求字典序最小. Input ...

  4. 【BZOJ4388】JOI2012 invitation 堆+线段树+并查集(模拟Prim)

    [BZOJ4388]JOI2012 invitation Description 澳洲猴举办了一场宴会,他想要邀请A个男生和B个女生参加,这A个男生从1到A编号,女生也从1到B编号.现在澳洲猴知道n组 ...

  5. BZOJ4919[Lydsy1706月赛]大根堆-------------线段树进阶

    是不是每做道线段树进阶都要写个题解..根本不会写 Description 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切 ...

  6. BZOJ.4919.[Lydsy1706月赛]大根堆(线段树合并/启发式合并)

    题目链接 考虑树退化为链的情况,就是求一个最长(严格)上升子序列. 对于树,不同子树间是互不影响的.仿照序列上的LIS,对每个点x维护一个状态集合,即合并其子节点后的集合,然后用val[x]替换掉第一 ...

  7. 【CF1023D】Array Restoration(构造,线段树)

    题意:有一个长为n的序列,对其进行q次操作,第i次操作可以把连续的一段覆盖为i 现在给出操作后的序列,第i个数字为a[i],其中有一些为0的位置可以为任意值,要求构造任意一组合法的操作后的序列 无解输 ...

  8. POJ 2991 Crane (线段树)

    题目链接 Description ACM has bought a new crane (crane -- jeřáb) . The crane consists of n segments of v ...

  9. 重识线段树——Let's start with the start.

    声明 本文为 Clouder 原创,在未经许可情况下请不要随意转载.原文链接 前言 一般地,这篇文章是给学习过线段树却仍不透彻者撰写的,因此在某些简单的操作上可能会一笔带过. 当然了,入门线段树后也可 ...

随机推荐

  1. 路由器基础配置之广播多路访问链路上的ospf

    我们将以上面的拓扑图进行实验,因为是要以不断广播的形式进行ospf,所有中间加了一个集线器,这种ospf和前一种不同,路由器之间会在配置好ospf之后选举出一个老大,DR,一个备份,BDR,而其他路由 ...

  2. JAVAOOP I/O

    程序的主要任务就是操作数据,通过允许程序读取文件的内容或向文件写入数据,可以使程序应用更加广泛. I/O(input/output) 在不同操作系统之下,所占的字节数也不同,一般认为 8.1.1使用F ...

  3. python 中的UDP和TCP(1)

    一.TCP: TCP是Transmission Control Protocol的简称,中文名传输控制协议.是一种面向连接的.可靠的.基于字节流的传输层通信协议.TCP通信需要经过创建连接.数据传输. ...

  4. C#中在WebClient中使用post发送数据实现方法

    很多时候,我们需要使用C#中的WebClient 来收发数据,WebClient 类提供向 URI 标识的任何本地.Intranet 或 Internet 资源发送数据以及从这些资源接收数据的公共方法 ...

  5. go学习笔记-面向对象(Methods, Interfaces)

    面向对象(Methods, Interfaces) Method method是附属在一个给定的类型上的,他的语法和函数的声明语法几乎一样,只是在func后面增加了一个receiver(也就是meth ...

  6. Kubernetes-深入分析集群安全机制

    Kubernetes过一系列机制来实现集群的安全机制,包括API Server的认证授权.准入控制机制及保护敏感信息的Secret机制等.集群的安全性必须考虑以下的几个目标: 保证容器与其所在宿主机的 ...

  7. Android面试收集录 2D绘图与动画技术

    1.如何在Android应用程序的窗口上绘制图形? 继承View 实现View中的onDraw()方法 2.如何绘制圆,空心椭圆? canvas.drawArc或canvas.drawCircle方法 ...

  8. 谈谈WPF中的CollectionView与CollectionViewSource (1)

    原文:谈谈WPF中的CollectionView与CollectionViewSource (1) 谈谈WPF中的CollectionView与CollectionViewSource (1)     ...

  9. android中接入twitter进行第三方登录

    在应用中接入Twitter进行第三方登录时,开发人员遇到了一点问题,主要是概念有点混乱,这里把经验记录一下,帮助遇到同样问题的朋友. 一.注册应用并配置登录权限 这一步比较简单,就不多说了,直接去官网 ...

  10. 汇编指令MOVSX与MOVZX

    MOVSX 操作数A ,操作数B MOVZX 操作数A ,操作数B 相同点:操作数B 空间必须小于 操作数A 1.格式与MOV基本相同 2.能完成小存储单元向大存储单元的数据传送 比如 movsx e ...