bzoj4345 Korale 优先队列&dfs

       首先构造出第k小的项链的权值。根据dfs求第k小的权值的流程类比,每一个项链可以用一个二元组(i,j)表示权值为i,最大的为j号(从小到大排序之后)。那么把这个二元组塞进优先队列,一个二元组(i,j)可以得到(i-a[j]+a[j+1],j+1)或者(i+a[j+1],j+1),然后一直拓展到k个为止。

       接着是求第k小。我们可以直接按照dfs,得到第k小,那么只要保证只dfs 1~k中的而2其他的不去搜索即可。那么可以用线段树得到(i,n)中比t小的最前面的元素,那么每次就不需要循环n个,这样保证值搜索到k个。

       因此总时间复杂度O(NlogN)。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#define N 1000005
#define ll long long
using namespace std;

int n,m,cnt,tp,a[N],num[N],val[N<<2],stk[N]; ll ans[N];
struct node{ ll x; int y; };
priority_queue<node> q;
bool operator <(node u,node v){
	return u.x>v.x;
}
int read(){
	int x=0; char ch=getchar();
	while (ch<'0' || ch>'9') ch=getchar();
	while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
	return x;
}
void build(int k,int l,int r){
	if (l==r){
		val[k]=a[l]; return;
	}
	int mid=(l+r)>>1;
	build(k<<1,l,mid); build(k<<1|1,mid+1,r);
	val[k]=min(val[k<<1],val[k<<1|1]);
}
int qry(int k,int l,int r,int x,ll y){
	if (x<=l){
		if (val[k]>y) return 0;
		if (l==r) return l;	
	}
	int mid=(l+r)>>1;
	if (x<=mid){
		int t=qry(k<<1,l,mid,x,y);
		if (t) return t;
	}
	return qry(k<<1|1,mid+1,r,x,y);
}
void dfs(int k,ll rst){
	if (!cnt) return; int i;
	if (!rst){
		cnt--;
		if (!cnt) for (i=1; i<=tp; i++) printf("%d ",stk[i]);
		return;
	}
	for (i=k+1; i<=n; i++){
		i=qry(1,1,n,i,rst);
		if (i){
			stk[++tp]=i; dfs(i,rst-a[i]); tp--;
		} else break;
	}
}
int main(){
	n=read(); m=read()-1; int i;
	if (!m){ puts("0"); return 0; }
	for (i=1; i<=n; i++) a[i]=num[i]=read();
	sort(num+1,num+n+1);
	node u; u.x=num[1]; u.y=1; q.push(u);
	for (i=1; i<=m; i++){
		u=q.top(); q.pop(); ans[i]=u.x;
		if (i<m && u.y<n){
			u.y++; u.x+=num[u.y]; q.push(u);
			u.x-=num[u.y-1]; q.push(u);
		}
	}
	for (i=m; i && ans[i]==ans[m]; i--) cnt++;
	printf("%lld\n",ans[m]);
	build(1,1,n); dfs(0,ans[m]);
	return 0;
}


by lych

2016.4.1

你可能感兴趣的:(线段树,优先队列,DFS,递推)