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
题解
妙啊…
尝试模拟爆搜的过程
把数组从小到大排序
设二元组 ( s u m , i ) (sum,i) (sum,i)表示当前总和为 s u m sum sum,最后一个数为 i i i
可以转移到 ( s u m − a [ i ] + a [ i + 1 ] , i ) (sum-a[i]+a[i+1],i) (sum−a[i]+a[i+1],i)和 ( s u m + a [ i + 1 ] , i ) (sum+a[i+1],i) (sum+a[i+1],i)
用一个堆模拟上述过程
由于每次加入的 s u m sum sum单调不减
所以模拟K次后得到的答案就是第K大的
记第K大的二元组共有m个
在原数组中进行构造
设 (答案-当前已经添加的数)=limit
根据上面模拟的过程 显然我们加的数单调不减
设最后一个数的位置是L,显然我们要在[L+1,n]这段区间里找到不比他小的数来爆搜
用线段树把他们一个个提出来就可以了…
每次加入后得到的数不超过limit
所以总状态数不超过K
复杂度 K log n K\log n Klogn
#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;
}