感觉..这道题好像和多校某题很像,当时那题我没做结果现在又不会做了..
现将珠子按价值排序
我们用一个二元组(x,i)代表当前选的珠子和为x,最后一个珠子是第i个
它可以转移到(x-a[i]+a[i+1],i+1),(x+a[i+1],i+1),且这种转移方式能不重不漏的覆盖所有的情况
又因为每次转移,新的状态和一定不比原来小,所以我们从(a[1],1)开始转移k-1次一定能得到第k小的价值,复杂度klogk
然后考虑寻找方案
我们在转移中记录第k小的价值有多少个,设为m个
又因为我们知道第k小的值x是多大,在寻找方案的时候,用原数组,假设当前方案最后一个数是第L-1个,x-已经取了的值=limit,那么我们在线段树上二分,在[L,n]里找不超过limit的数一个一个取出来,
因为我们每次取一个不超过限制的数,都代表拓展到了一个不超过第k小的状态,而且每次拓展的状态互不相同,所以最多拓展k次,每次在线段树上耗费logn,复杂度klogn
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1e9
using namespace std;
const int maxn = 1100000;
int n,m;
struct node
{
ll x;
int i;
};
inline bool operator <(const node x,const node y){return x.x>y.x;}
priority_queue<node>q;
int a[maxn],b[maxn];
int seg[maxn<<2];
void build(const int x,const int l,const int r)
{
if(l==r) { seg[x]=a[l]; return; }
int mid=l+r>>1,lc=x<<1,rc=lc|1;
build(lc,l,mid); build(rc,mid+1,r);
seg[x]=min(seg[lc],seg[rc]);
}
int lx; ll u;
int search(const int x,const int l,const int r)
{
if(l==r) return l;
int mid=l+r>>1,lc=x<<1,rc=lc|1;
if(seg[lc]<=u) return search(lc,l,mid);
else return search(rc,mid+1,r);
}
int query(const int x,const int l,const int r)
{
if(r<lx||seg[x]>u) return -1;
if(l>=lx) return search(x,l,r);
int mid=l+r>>1,lc=x<<1,rc=lc|1;
int rl=query(lc,l,mid);
if(rl!=-1) return rl;
return query(rc,mid+1,r);
}
int t[maxn],tp,now,sn;
void dfs(const ll limit,int L)
{
if(!limit)
{
now++; if(now==sn) return;
return;
}
while(1)
{
lx=L,u=limit; if(lx>n) return;
int tmp=query(1,1,n);
if(tmp==-1) return;
t[++tp]=tmp,L=tmp+1;
dfs(limit-b[tmp],L);
if(now==sn) return;
tp--;
}
}
int main()
{
scanf("%d%d",&n,&m);
if(m==1) { printf("0\n");return 0; } m--;
for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];
build(1,1,n);
sort(a+1,a+n+1);
ll s=-1;
q.push((node){a[1],1});
for(int i=1;i<=m;i++)
{
const node tmp=q.top(); q.pop();
if(tmp.x!=s) s=tmp.x,sn=1;
else sn++;
if(tmp.i<n) q.push((node){tmp.x-a[tmp.i]+a[tmp.i+1],tmp.i+1}),q.push((node){tmp.x+a[tmp.i+1],tmp.i+1});
}
tp=0,dfs(s,1);
printf("%lld\n",s);
for(int i=1;i<=tp;i++) printf("%d ",t[i]);
return 0;
}