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