zoukankan      html  css  js  c++  java
  • [HNOI/AHOI2018]排列(贪心)

    opening

    题目链接

    好像之前模拟赛考过原题,不过这个题的题意是真的看不懂,还有题解区都说省选出原题,原来省选都会出原题的呀,我吐了。

    outline

    给数组 (a)(0 <= a_i <= n)) 和 (w),它的一个排列合法当且仅当对于 (p[j] <= p[k]),那么不存在 (a_{p[j]} == p[k]),定义该排列的价值为 (sum_{1}^{n}i*w_{p_i}),要求是价值最大化。

    solution

    反正在没有看题解之前我连题意都读不懂,u1s1,这道省选题出的是真的烂啊,不过题中的套路还是不错的。

    我们可以把题意转化为对于 (a[i] = k),那么在 (p) 数组里 (k) 要放到 (i) 的前面,我们考虑建图,对于这样的情况我们 (k->i),即 (k) 连向 (i)

    图如果是一棵基环树,那么本题无解,否则是一棵以 (0) 为根的树,题目转化为给定一棵树,每个节点都有一个价值,要求选一个节点必须先选它的父亲,求最大价值。

    我们不难想到经典的套路题,取出当前 (w) 最小的点,如果它已经没有父亲了,那么直接计算答案,否则把它和它的父亲合并成一个点,且新点的权值定义为它们权值的平均数,然后重复该过程,得到的便是答案。

    对于为啥是权值的平均值,这个是可以推柿子的,因为每次合并相当于两个序列合并,随便推一下柿子就可以得到平均值的结论了。

    其实这道题的实现方法还是挺值得研究的,主要是利用堆来实现,并且用并查集来维护联通块和最新的情况,方便即时排除堆中过时的元素,利用0号节点方便直接计算答案。

    std

    
    // by longdie 
    #include <bits/stdc++.h> 
    #define ll long long 
    using namespace std; 
    const int N = 5e5 + 5; 
    ll ans, w[N]; 
    int n, a[N], fa[N], siz[N]; 
    struct node {
    	int id; ll val, num; 
    	node() {}
    	node(int a, ll b, ll c) { id = a, val = b, num = c; } 
    	friend bool operator < (const node &a, const node &b) {
    		return a.val * b.num > b.val * a.num; 
    	}
    }; priority_queue<node> q; 
    inline int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); } 
    inline void merge(int x, int y) { fa[find(x)] = find(y); } 
    signed main() {
    	scanf("%d", &n); 
    	for(register int i = 0; i <= n; ++i) fa[i] = i, siz[i] = 1; 
    	for(register int i = 1; i <= n; ++i) {
    		scanf("%d", &a[i]); 
    		if(find(a[i]) == find(i)) return puts("-1"), 0; 
    		merge(a[i], i); 
    	}
    	for(register int i = 0; i <= n; ++i) fa[i] = i, siz[i] = 1; 
    	for(register int i = 1; i <= n; ++i) 
    		scanf("%lld", &w[i]), q.push(node(i, w[i], 1));
    	while(q.size()) {
    		node t = q.top(); q.pop(); 
    		int u = find(t.id), v = find(a[u]); 
    		if(t.num != siz[u]) continue; 
    		ans += w[u] * siz[v]; 
    		w[v] += w[u], siz[v] += siz[u]; 
    		merge(u, v); 
    		if(v) q.push(node(v, w[v], siz[v]));  
    	}
    	cout << ans << '
    '; 
    	return 0; 
    }
    
  • 相关阅读:
    ActiveReport9 在MVC4项目中出错
    EntityFramework5.0 DataBase-First 在三层架构中的使用,分离实体类到Model层。
    SqlServer存在并删除 表,函数,view等
    Visual Studio常用技巧与插件
    让 WPF 应用程序单例化
    C# 常用加密方法一 AES 与 DES
    Windows 的公共文件夹
    Hibernate中Criteria的完整用法
    maven依赖关系中Scope的作用
    Eclipse取消设置项目默认空间
  • 原文地址:https://www.cnblogs.com/longdie/p/14520652.html
Copyright © 2011-2022 走看看