[bzoj4345][線段樹][優先佇列]Korale
阿新 • • 發佈:2018-12-12
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
題解
妙啊… 嘗試模擬爆搜的過程 把陣列從小到大排序 設二元組表示當前總和為,最後一個數為 可以轉移到和 用一個堆模擬上述過程 由於每次加入的單調不減 所以模擬K次後得到的答案就是第K大的 記第K大的二元組共有m個 在原陣列中進行構造 設 (答案-當前已經新增的數)=limit 根據上面模擬的過程 顯然我們加的數單調不減 設最後一個數的位置是L,顯然我們要在[L+1,n]這段區間裡找到不比他小的數來爆搜 用線段樹把他們一個個提出來就可以了… 每次加入後得到的數不超過limit 所以總狀態數不超過K 複雜度
#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; }