Bzoj4345 [poi2016]korale

线段树+dfs寻找方案

阅读全文大概需要 1分钟
本文总阅读量
Posted by yjjr's blog on April 8, 2018

标签:线段树,dfs,堆

题目

题目传送门

Description

有n个带标号的珠子,第i个珠子的价值为a[i]。现在你可以选择若干个珠子组成项链(也可以一个都不选),项链的价值为所有珠子的价值和。

现在给所有可能的项链排序,先按权值从小到大排序,对于权值相同的,根据所用珠子集合的标号的字典序从小到大排序。

请输出第k小的项链的价值,以及所用的珠子集合。

Input

第一行包含两个正整数\(n,k(1\leq n\leq 1000000,1\leq k\leq min(2^n,1000000))\)。

第二行包含n个正整数,依次表示每个珠子的价值\(a[i](1\leq a[i]\leq 10^9)\)。

Output

第一行输出第k小的项链的价值。

第二行按标号从小到大依次输出该项链里每个珠子的标号。

Sample Input

4 10
3 7 4 3

Sample Output

10
1 3 4

分析

每一条项链可以用一个二元组\((i,j)\)表示权值为i,最大的为j号(从小到大排序之后)

那么把这个二元组放进堆中,\((i,j)\)可以拓展到\((i-a[j]+a[j+1],j+1)\)或者\((i+a[j+1],j+1)\),然后一直拓展到k个为止

因为每次转移,新的状态和肯定只会比之前的大或相等,所以我们从\((a[1],1)\)开始转移\(k-1\)次一定能得到第k小的价值,复杂度\(O(k \log k)\)


难点在于如何寻找方案

我们可以直接dfs,得到第k小,那么只要保证只搜索\(1->k\)中的状态即可

那么可以用线段树得到\((i,n)\)中比t小的最前面的元素,那么每次就不需要循环n个,这样保证只搜索到k个

总的时间复杂度为\(O(k \log n)\)

code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
#define mem(x,num) memset(x,num,sizeof x)
#define reg(x) for(int i=last[x];i;i=e[i].next)
using namespace std;
inline ll read(){
	ll f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
//**********head by yjjr**********
#define mid ((l+r)>>1)
#define lson p<<1
#define rson p<<1|1 
const int maxn=1e6+6;
int n,m,cnt,top,a[maxn],num[maxn],val[maxn<<2],stk[maxn];ll ans[maxn];
struct node{ll val;int id;};
priority_queue<node> q;
inline bool operator < (node a,node b){return a.val>b.val;}
void build(int p,int l,int r){
	if(l==r){val[p]=a[l];return;}
	build(lson,l,mid);build(rson,mid+1,r);
	val[p]=min(val[lson],val[rson]);
}
inline int query(int p,int l,int r,int Q,ll y){
	if(Q<=l){
		if(val[p]>y)return 0;
		if(l==r)return l;
	}
	if(Q<=mid){
		int t=query(lson,l,mid,Q,y);
		if(t)return t;
	}
	return query(rson,mid+1,r,Q,y);
}
void dfs(int k,ll rst){
	if(!cnt)return;int i;
	if(!rst){
		cnt--;
		if(!cnt)for(i=1;i<=top;i++)printf("%d ",stk[i]);
		return;
	}
	for(i=k+1;i<=n;i++){
		i=query(1,1,n,i,rst);
		if(i){
			stk[++top]=i;dfs(i,rst-a[i]);top--;
		}else break;
	}
}
int main()
{
	n=read(),m=read()-1;
	if(!m){puts("0");return 0;}
	rep(i,1,n)a[i]=num[i]=read();
	sort(num+1,num+1+n);
	node u={num[1],1};q.push(u);
	rep(i,1,m){
		node now=q.top();q.pop();ans[i]=now.val;
		if(i<m&&now.id<n){
			now.id++;now.val+=num[now.id];q.push(now);
			now.val-=num[now.id-1];q.push(now);
		}
	}
	for(int i=m;i&&ans[i]==ans[m];i--)cnt++;
	printf("%lld\n",ans[m]);
	build(1,1,n);dfs(0,ans[m]);
	return 0;
}
本文可以转载,但必须附上原文链接,否则你会终生找不到妹子!!!欢迎关注我的CSDN: ahyjjr