[HNOI 2018]排列
Description
给定 \(n\) 个整数 \(a_1, a_2, \dots, a_n, 0 \le a_i \le n\) ,以及 \(n\) 个整数 \(w_1, w_2, \dots, w_n\) 。称 \(a_1, a_2, \dots, a_n\) 的 一个排列 \(a_{p[1]}, a_{p[2]}, \dots, a_{p[n]}\) 为 \(a_1, a_2, \dots, a_n\) 的一个合法排列,当且仅当该排列满足:对于任意的 \(k\) 和任意的 \(j\) ,如果 \(p[k]\) 等于 \(a_{p[j]}\) ,那么 \(k<j\) 。定义这个合法排列的权值为 \(w_{p[1]} + 2w_{p[2]} + \dots + nw_{p[n]}\) 。
求出在所有合法排列中的最大权值。如果不存在合法排列,输出 \(-1\) 。
\(1\leq n\leq 500000,0\leq a_i\leq n,1\leq w_i\leq 10^9\) ,\(\sum w_i\leq 1.5\times 10^{13}\)
Solution
假如我们对于所有的 \(i\) , \(a[i]\) 和 \(i\) 间建一条边,显然这副图可能构成了一棵树。
如果不存在合法排列,当前仅当构成的图非树。
如何构成了树,那么原题的模型就变成了:给出一棵以 \(0\) 为根的有根树,需要为非 \(0\) 顶点标号 \(1\sim n\) ,并且满足父亲比自己先标号。每个节点有点权,树的价值为点权乘标号的和。求树最大的价值。
一个显然的贪心是如果当前树中权值最小的点 \(u\) 没有父亲,那么我们当前一定是选 \(u\) 。
不过大部分不是这种情况。
考虑如果 \(u\) 有父亲,显然当他的父亲被选之后马上就会选 \(u\) ,也就是说父子间的编号一定是相邻的。我们可以将 \(u\) 的答案并在他的父亲中。
同样的,对于两个不同的“块”,也是如此。
考虑一个长度为 \(l_1\) 的序列 \(A\) 和一个长度为 \(l_2\) 的序列 \(B\) ,
序列前面已经安排好了 \(loc\) 个。考虑 \(AB\) 和 \(BA\) 两种合并后的序列的答案:
\[W_{AB}=\sum_{i=1}^{l_1}(i+loc)w_{A_i}+\sum_{i=1}^{l_2}(i+loc+l_1)w_{B_i}\]
\[W_{BA}=\sum_{i=1}^{l_2}(i+loc)w_{B_i}+\sum_{i=1}^{l_1}(i+loc+l_2)w_{A_i}\]
如果 \(W_{AB}> W_{BA}\Rightarrow \frac{\sum_{i=1}^{l_1}w_{A_i}}{l_1}<\frac{\sum_{i=1}^{l_2}w_{B_i}}{l_2}\)
也就是平均权值小的放前面答案会更优。
那么我们就可以用堆来维护这个东西。
不知道为什么写了个支持删除的堆只有 50 ,然而不删去而在取出堆顶时判断是否合法就对了...
Code
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 500000+5;
int n, a[N], fa[N], sz[N]; ll w[N];
struct node {
int id; ll son, mom;
node (int _id = 0, ll _son = 0, ll _mom = 0) {id = _id, son = _son; mom = _mom; }
bool operator < (const node &b) const {return son*b.mom > b.son*mom; }
};
priority_queue<node>Q;
int find(int o) {return ~fa[o] ? fa[o] = find(fa[o]) : o; }
void work() {
memset(fa, -1, sizeof(fa));
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
if (find(a[i])^find(i)) fa[find(a[i])] = find(i);
else {puts("-1"); return; }
}
long long ans = 0; int loc = 0;
for (int i = 1; i <= n; i++) {
scanf("%lld", &w[i]); Q.push(node(i, w[i], 1));
sz[i] = 1; ans += w[i];
}
memset(fa, -1, sizeof(fa));
while (!Q.empty()) {
node t = Q.top(); Q.pop();
if (sz[t.id] != t.mom) continue;
if (find(a[t.id]) == 0) {
ans += w[t.id]*loc; fa[t.id] = 0; loc += sz[t.id];
}else {
int tmp = find(a[t.id]);
ans += w[t.id]*sz[tmp], fa[t.id] = tmp;
w[tmp] += w[t.id], sz[tmp] += sz[t.id];
Q.push(node(tmp, w[tmp], sz[tmp]));
}
}
printf("%lld\n", ans);
}
int main() {work(); return 0; }
[HNOI 2018]排列的更多相关文章
- 【LG4437】[HNOI/AHOI2018]排列
[LG4437][HNOI/AHOI2018]排列 题面 洛谷 题解 题面里这个毒瘤的东西我们转化一下: 对于\(\forall k,j\),若\(p_k=a_{p_j}\),则\(k<j\). ...
- 【HNOI 2018】排列
Problem Description 给定 \(n\) 个整数 \(a_1, a_2, \ldots , a_n(0 \le a_i \le n)\),以及 \(n\) 个整数 \(w_1, w_2 ...
- HNOI 2018 简要题解
寻宝游戏 毒瘤题. 估计考试只会前30pts30pts30pts暴力然后果断走人. 正解是考虑到一个数&1\&1&1和∣0|0∣0都没有变化,&0\&0& ...
- [HNOI/AHOI2018]排列 贪心
题面 题解: 把题面的限制换成中文: 如果排在第k位的下标 = 排在第j位的值 ,那么k < j 换一个描述方式: 一个值为x的数要排在第x个数后面. 再换一个描述方式: \(fa[i] = a ...
- [HNOI/AHOI2018]排列
[Luogu4437] 如果\(a[i]=j\)则序列\(p[]\)中\(j\)必须排在\(i\)前面,如果\(j\)不在范围内则不管,求一个式子\(\sum_{i=1}^n iw_{p[i]}\)的 ...
- 洛谷 P4437 [HNOI/AHOI2018]排列(贪心+堆,思维题)
题面传送门 开始 WA ycx 的遗产(bushi 首先可以将题目转化为图论模型:\(\forall i\) 连边 \(a_i\to i\),然后求图的一个拓扑序 \(b_1,b_2,\dots b_ ...
- [HNOI 2018]道路
Description 题库链接 给出一棵含有 \(n\) 个叶子节点的二叉树,对于每个非叶子节点的节点,其与左儿子相连的边为公路,其与右儿子相连的边为铁路.对于每个节点,选择一条与其儿子相连的铁路或 ...
- [HNOI 2018]游戏
Description 题库链接 有 \(n\) 个房间排成一列,编号为 \(1,2,...,n\) ,相邻的房间之间都有一道门.其中 \(m\) 个门上锁,其余的门都能直接打开.现在已知每把锁的钥匙 ...
- 【HNOI 2018】毒瘤
Problem Description 从前有一名毒瘤. 毒瘤最近发现了量产毒瘤题的奥秘.考虑如下类型的数据结构题:给出一个数组,要求支持若干种奇奇怪怪的修改操作(例如给一个区间内的数同时加上 \(c ...
随机推荐
- 跨平台原生AR/VR应用研发引擎-NVisionXR开放内测
NVisionXR引擎正式开放内测.现在,对原生AR/VR应用开发有兴趣的企业和开发者均可通过NVisionXR官网(www.nvisionxr.com)申请试用. NVisionXR引擎介绍视频 ...
- Struts2学习笔记二 配置详解
Struts2执行流程 1.简单执行流程,如下所示: 在浏览器输入请求地址,首先会被过滤器处理,然后查找主配置文件,然后根据地址栏中输入的/hello去每个package中查找为/hello的name ...
- 网络1711班 C语言第八次作业批改总结
网络1711班 C语言第七次作业批改总结 最近在忙一些琐事,没能及时批改大家的作业,连续两次作业总结也没有很用心写,在这要给大家say sorry. 1.本次作业评分细则 1.1 基本要求(1分) 按 ...
- C语言博客作业—数据类型
一.PTA实验作业 题目1: 1. 本题PTA提交列表 2. 设计思路 (2)if(输入的n为奇数){ for(行数小于n/2+1时){ for(空格数等于n-2*k+1) printf(" ...
- C语言数据类型作业
一.PTA实验作业 题目1:7-4 打印菱形图案 1. 本题PTA提交列表 2. 设计思路 1.定义m,n(用于计算空格数,输出"* "数),i,j,k(用于循环) 2.输入n,并 ...
- python实现朴素贝叶斯
参考:<机器学习实战>- Machine Learning in Action 一. 基本思想 简单的说,用概率的高低来决定数据属于哪一类别,这就是贝叶斯决策理论的核心思想,即选择具有最 ...
- HTML5文件操作API
HTML5文件操作API 一.文件操作API 在之前我们操作本地文件都是使用flash.silverlight或者第三方的activeX插件等技术,由于使用了这些技术后就很难进行跨平台.或 ...
- JavaScript 相关知识
一.数组 var a = [1,2,3,4]; console.log(a.length); a.push(5); console.log(a); // [1, 2, 3, 4, 5] var r ...
- zookeeper入门系列:paxos协议
上一章讨论了一种强一致性的情况,即需要分布式事务来解决,本章我们来讨论一种最终一致的算法,paxos算法. paxos算法是由大牛lamport发明的,关于paxos算法有很多趣事.比如lamport ...
- Ubuntu server 16.04 中文版 终端不能显示中文的解决办法探讨
对于刚安装成功的Ubuntu server 16.04中文版,在终端显示中文的地方总是出现菱形的图标,看来该版本内置终端暂时不支持中文显示, 还是本人不知道具体操作配置,现通过百度查找以下几个解决方案 ...