洛谷&BZOJ [POI2016]Korale

[POI2016]Korale题解

题目链接: P5967

不妨把题目的分为两问

Part1: 求出第k小的项链组合价值

思路类似超级钢琴, 先将价值排序, 用二元组((sum, i)) 描述前i个数选出若干数和为sum(必选第i个数), 利用小根堆不断取出堆顶, 并把((sum + a[i+1], i+1))((sum + a[i+1] - a[i], i + 1))加入堆中. 这种方法可以将所有情况不重不漏遍历且具有单调性, 时间复杂度(Theta(klogn))

Part2: 求出所用珠子集合

设上一问求出的答案为ans, 排名小于等于k且和为ans的个数为cnt

爆搜: 从前向后取数, 每次尽量取靠前的数, 从而保证字典序最小, 取数可以用线段树维护区间最小值, 用st表也是可以的, 因为取得集合排名一定小于等于k, 所以最多选出k次, 复杂的(Theta(klogn))

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <algorithm>
#define ll long long
using namespace std;
const int N = 1005000;

template <typename T>
void read(T &x) {
    x = 0; bool f = 0;
    char c = getchar();
    for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
    for (;isdigit(c);c=getchar()) x=x*10+(c^48);
    if (f) x=-x;
}

template <typename T>
void write(T x) {
    if (x < 0) putchar('-'), x = -x;
    if (x >= 10) write(x / 10);
    putchar('0' + x % 10);
}

int n, k;

int a[N], b[N];

struct node {
	ll sum, i;
	bool operator < (const node &i) const {
		return sum > i.sum;
	}
};

priority_queue <node> q;
ll ans, cnt;

#define p1 p << 1
#define p2 p << 1 | 1
int mn[N<<2];

inline int Mn(int a, int b) {return a > b ? b : a;}
	

void build(int l, int r, int p) {
	if (l == r) return mn[p] = a[l], void();
	int mid = (l + r) >> 1;
	build(l, mid, p1), build(mid + 1, r, p2);
	mn[p] = Mn(mn[p1], mn[p2]);
}

int query(int l, int r, int p, int ql, ll x) {
	if (ql <= l) {
		if (mn[p] > x) return 0;
		if (l == r) return l;
	}
	int mid = (l + r) >> 1;
	if (ql <= mid) {
		int t = query(l, mid, p1, ql, x);
		if (t) return t;
	}
	return query(mid + 1, r, p2, ql, x);
}

int top, st[N];
void dfs(int l, ll res) {
	if (!res) {
		cnt--;
		if (!cnt) {
			cout << ans << endl;
			for (int i = 1;i <= top; i++) 
				write(st[i]), putchar(' ');
			exit(0);
		}
	}
	for (int i = l + 1;i <= n; i++) {
		i = query(1, n, 1, i, res);
		if (!i) return;
		st[++top] = i;
		dfs(i, res - a[i]);
		top--;
	}
}

int main() {
	read(n), read(k); k--;
	if (k == 0) {
		cout << 0 << endl;
		return 0;
	}
	for (int i = 1;i <= n; i++) read(a[i]), b[i] = a[i];
	sort(b + 1, b + n + 1); q.push((node){b[1], 1});
	for (int i = 1;i <= k; i++) {
		node tmp = q.top(); q.pop();
		if (tmp.sum == ans) cnt++;
		else ans = tmp.sum, cnt = 1;
		if (tmp.i == n) continue;
		tmp.i++, tmp.sum += b[tmp.i];
		q.push(tmp); tmp.sum -= b[tmp.i-1]; q.push(tmp);
	}
	build(1, n, 1); dfs(0, ans);
	return 0;
}
原文地址:https://www.cnblogs.com/Hs-black/p/12234065.html