首先构造出第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