1. 程式人生 > >[bzoj4345][線段樹][優先佇列]Korale

[bzoj4345][線段樹][優先佇列]Korale

Description

有n個帶標號的珠子,第i個珠子的價值為a[i]。現在你可以選擇若干個珠子組成項鍊(也可以一個都不選),項鍊的價值為所有珠子的價值和。現在給所有可能的項鍊排序,先按權值從小到大排序,對於權值相同的,根據所用珠子集合的標號的字典序從小到大排序。請輸出第k小的項鍊的價值,以及所用的珠子集合。

Input

第一行包含兩個正整數n,k(1<=n<=1000000,1<=k<=min(2^n,1000000))。 第二行包含n個正整數,依次表示每個珠子的價值ai

Output

第一行輸出第k小的項鍊的價值。 第二行按標號從小到大依次輸出該項鍊裡每個珠子的標號。

Sample Input

4 10

3 7 4 3

Sample Output

10

1 3 4

題解

妙啊… 嘗試模擬爆搜的過程 把陣列從小到大排序 設二元組(sum,i)(sum,i)表示當前總和為sumsum,最後一個數為ii 可以轉移到(suma[i]+a[i+1],i)(sum-a[i]+a[i+1],i)(sum+a[i+1],i)(sum+a[i+1],i) 用一個堆模擬上述過程 由於每次加入的sumsum單調不減 所以模擬K次後得到的答案就是第K大的 記第K大的二元組共有m個 在原陣列中進行構造 設 (答案-當前已經新增的數)=limit 根據上面模擬的過程 顯然我們加的數單調不減 設最後一個數的位置是L,顯然我們要在[L+1,n]這段區間裡找到不比他小的數來爆搜 用線段樹把他們一個個提出來就可以了… 每次加入後得到的數不超過limit 所以總狀態數不超過K 複雜度K

lognK\log n

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define lc now<<1
#define rc now<<1|1
using namespace std;
inline int read()
{
	int 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;
}
inline void write(int x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+'0');
}
inline void print(int x){write(x);printf(" ");}
int mn[4110000],a[1110000],b[1110000];
void build(int now,int l,int r)
{
	if(l==r){mn[now]=a[l];return ;}
	int mid=(l+r)/2;
	build(lc,l,mid);build(rc,mid+1,r);
	mn[now]=min(mn[lc],mn[rc]);
}
int findpos(int now,int l,int r,LL u)
{
	if(l==r)return l;
	int mid=(l+r)/2;
	if(mn[lc]<=u)return findpos(lc,l,mid,u);
	else return findpos(rc,mid+1,r,u);
}
int lpos;
int query(int now,int l,int r,LL u)
{
	if(r<lpos||mn[now]>u)return -1;
	if(l>=lpos)return findpos(now,l,r,u);
	int mid=(l+r)/2;
	int tmp=query(lc,l,mid,u);
	if(tmp!=-1)return tmp;
	return query(rc,mid+1,r,u);
}
priority_queue<pair<LL,int>,vector<pair<LL,int> >,greater<pair<LL,int> > > q;
int n,m,now,ct,sta[1110000],tp;
void dfs(LL limit,int L)
{
	if(!limit){now++;return ;}
	while(1)
	{
		lpos=L;if(lpos>n)break;
		int ta=query(1,1,n,limit);
		if(ta==-1)break;
		sta[++tp]=ta;L=ta+1;
		dfs(limit-a[ta],L);
		if(now==ct)return;
		tp--;
	}
}
int main()
{
	n=read();m=read();
	if(m==1){puts("0");return 0;}m--;
	for(int i=1;i<=n;i++)b[i]=a[i]=read();
	build(1,1,n);
	sort(b+1,b+1+n);
	LL s=-1;
	q.push(mp(b[1],1));
	for(int i=1;i<=m;i++)
	{
		LL s1=q.top().first;int pa=q.top().second;q.pop();
		if(s1!=s)s=s1,ct=1;
		else ct++;
		if(pa!=n)q.push(mp(s1+b[pa+1],pa+1)),q.push(mp(s1-b[pa]+b[pa+1],pa+1));
	}
	dfs(s,1);
	printf("%lld\n",s);
	for(int i=1;i<=tp;i++)print(sta[i]);
	return 0;
}