• 洛谷&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;
    }
    
  • 相关阅读:
    创建型设计模式之-单例
    设计模式(1、创造型2、结构型、3行为型)
    手写IOC容器和两种注入(构造方法注入和属性注入)
    从依赖倒置原则到IOC控制反转
    自定义HttpHandler可以做什么
    一个用户在浏览器上输入网址怎么走到我们写的.net程序中的,请求到管道处理
    代理Nginx
    .Net Expression表达式目录树(自己动态创建表达式目录树)
    canvas绘制圆环进度条
    城市二级联动
  • 原文地址:https://www.cnblogs.com/Hs-black/p/12234065.html
Copyright © 2020-2023  润新知