【LG4437】[HNOI/AHOI2018]排列

题面

洛谷

题解

题面里这个毒瘤的东西我们转化一下:

对于\(\forall k,j\),若\(p_k=a_{p_j}\),则\(k<j\)。

也就是说若\(y=a_x\),则\(y\)排在\(x\)前面,

那么我们在原数组编号中\(a_x\)向\(x\)连边可以表示出这种拓扑关系。

那么我们连玩边后肯定是以\(0\)为根的一颗有根树,否则一定会形成一个环,无解。

贪心地想一下,对于权值最小的点,我们肯定让它尽量往前选,那么在它父亲选完后,我们一定会选它,所以我们可以考虑把它的权值并到它父亲上。

这样子的话,我们每个点就变成了一个序列,

考虑两个序列\(a,b\)的合并方式决定最优答案(当前已经到了第\(i\)位):

\[W_{ab}=\sum_{j=1}^{m_1}(i+j)w_{a_j}+\sum_{j=1}^{m_2}(i+j+m_1)w_{b_j}​\\
W_{ba}=\sum_{j=1}^{m_2}(i+j)w_{b_j}+\sum_{j=1}^{m_1}(i+j+m_2)w_{a_j}​\\
W_{ab}-W_{ba}=m_1W_b-m_2W_a​
\]

那么如果\(W_{ab}>W_{ba}\)则\(\frac{W_a}{m_1}<\frac{W_b}{m_2}​\),也就是平均数小的放前面。

具体实现详见代码。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
inline int gi() {
register int data = 0, w = 1;
register char ch = 0;
while (!isdigit(ch) && ch != '-') ch = getchar();
if (ch == '-') w = -1, ch = getchar();
while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar();
return w * data;
}
const int MAX_N = 5e5 + 5;
struct Graph { int next, to; } e[MAX_N << 1]; int fir[MAX_N], e_cnt;
void clearGraph() { memset(fir, -1, sizeof(fir)); e_cnt = 0; }
void Add_Edge(int u, int v) { e[e_cnt] = (Graph){fir[u], v}; fir[u] = e_cnt++; }
bool vis[MAX_N];
int N, tot, pa[MAX_N], fa[MAX_N], size[MAX_N];
long long w[MAX_N];
void dfs(int x) {
vis[x] = 1, ++tot;
for (int i = fir[x]; ~i; i = e[i].next) {
int v = e[i].to;
if (vis[v]) { puts("-1"); exit(0); }
else dfs(v);
}
}
int getf(int x) { return pa[x] == x ? x : pa[x] = getf(pa[x]); } struct Node { int u, sz; long long w; } ;
bool operator < (const Node &l, const Node &r) { return l.w * r.sz > r.w * l.sz; }
struct Heap{
Node h[MAX_N]; int cur;
Node top() { return h[1]; }
void push(const Node &x) { h[++cur] = x; push_heap(&h[1], &h[cur + 1]); }
void pop() { pop_heap(&h[1], &h[cur + 1]); --cur; }
bool empty() { return cur == 0; }
} que;
int main () {
#ifndef ONLINE_JUDGE
freopen("cpp.in", "r", stdin);
#endif
clearGraph();
N = gi();
for (int i = 1; i <= N; i++) fa[i] = gi(), Add_Edge(fa[i], i);
for (int i = 1; i <= N; i++) w[i] = gi();
dfs(0); if (tot <= N) return puts("-1") & 0;
for (int i = 0; i <= N; i++) pa[i] = i, size[i] = 1;
for (int i = 1; i <= N; i++) que.push((Node){i, 1, w[i]});
long long ans = 0;
while (!que.empty()) {
Node p = que.top(); que.pop();
int u = getf(p.u);
if (size[u] != p.sz) continue;
int f = getf(fa[u]); pa[u] = f;
ans += w[u] * size[f], w[f] += w[u], size[f] += size[u];
if (f) que.push((Node){f, size[f], w[f]});
}
printf("%lld\n", ans);
return 0;
}

【LG4437】[HNOI/AHOI2018]排列的更多相关文章

  1. [HNOI/AHOI2018]排列 贪心

    题面 题解: 把题面的限制换成中文: 如果排在第k位的下标 = 排在第j位的值 ,那么k < j 换一个描述方式: 一个值为x的数要排在第x个数后面. 再换一个描述方式: \(fa[i] = a ...

  2. [HNOI/AHOI2018]排列

    [Luogu4437] 如果\(a[i]=j\)则序列\(p[]\)中\(j\)必须排在\(i\)前面,如果\(j\)不在范围内则不管,求一个式子\(\sum_{i=1}^n iw_{p[i]}\)的 ...

  3. 洛谷 P4437 [HNOI/AHOI2018]排列(贪心+堆,思维题)

    题面传送门 开始 WA ycx 的遗产(bushi 首先可以将题目转化为图论模型:\(\forall i\) 连边 \(a_i\to i\),然后求图的一个拓扑序 \(b_1,b_2,\dots b_ ...

  4. BZOJ5289 HNOI/AHOI2018排列(贪心+堆)

    题面描述的相当绕,其实就是如果ai=j,重排后ai要在aj之后.同时每个ai有附属属性wi,要求最大化重排后的Σiwi. 容易发现这事实上构成一张图,即由j向i连边.由于每个点入度为1或0,该图是基环 ...

  5. 【洛谷 P4437】 [HNOI/AHOI2018]排列(贪心,堆)

    题目链接 如果\(j<=k,a_{p[j]}!=p[k]\)可以理解为如果\(a_{p[j]}=p[k]\),那么\(k\)一定要放在\(j\)前面,也就是\(a_j\)在\(j\)前面. 于是 ...

  6. BZOJ5289 & 洛谷4437:[HNOI/AHOI2018]排列——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=5289 https://www.luogu.org/problemnew/show/P4437 考虑 ...

  7. Poj2054 color a tree && [HNOI/AHOI2018]排列

    https://zybuluo.com/ysner/note/1120723 题面 原题 某省选强化题 大致意思是给你一颗树,选父亲后才能选儿子. 每个点对答案的贡献为你在第几次选这个点 × 该点权值 ...

  8. luogu P4437 [HNOI/AHOI2018]排列

    luogu 问题本质是把\(a_i\)作为\(i\)的父亲,然后如果有环就不合法,否则每次要取数,要满足取之前他的父亲都被取过(父亲为0可以直接取),求最大价值 贪心想法显然是要把权值大的尽量放在后面 ...

  9. 【题解】Luogu P4436 [HNOI/AHOI2018]游戏

    原题传送门 \(n^2\)过百万在HNOI/AHOI2018中真的成功了qwqwq 先将没门分格的地方连起来,枚举每一个块,看向左向右最多能走多远,最坏复杂度\(O(n^2)\),但出题人竟然没卡(建 ...

随机推荐

  1. 在windows下使用VirtualEnv建立flask项目

    1.系统中安装VirtualEnv 在安装完Python后,自带的有pip或easy_install工具,可进行VirtualEnv的安装 pip install virtualenv 2.构造项目, ...

  2. 三、Spring注解之@Import

    spring注解之@Import [1]@Import ​ 参数value接收一个Class数组,将你传入的类以全类名作为id加入IOC容器中 ​ 比较简单,此处不做详细解释 [2]ImportSel ...

  3. vue+element 动态表单验证

    公司最近的项目有个添加动态表单的需求,总结一下我在表单验证上遇到的一些坑. 如图是功能的需求,这个功能挺好实现的,但是表单验证真是耗费了我一些功夫. vue+element在表单验证上有一些限制,必须 ...

  4. 将Excel表格数据转换成Datatable

    /// <summary> /// 将Excel表格数据转换成Datatable /// </summary> /// <param name="fileUrl ...

  5. dedecms5.7的获取本文章的TAG

    tag调用标签如下: {dede:tag row='10' getall='1' sort='month'} <li><a href='[field:link/]'>[fiel ...

  6. C#面试基础知识点:值类型和引用类型(1)(填坑文)

    目录 前言 C#值类型和引用类型 基类(共同点) 值类型继承基类(不同点) 应用类型继承 技术经理的问题 值类型与引用类型都可以用Equals来比较吗? 如何将一个数组a的值赋予数组b然后对b做修改而 ...

  7. 页面直接导出为PDF文件,支持分页与页边距

    将WEB页面直接导出为pdf文件是经常会用到的一个功能,尤其是各种报表系统.总结了一下目前几种主流的做法: 在后端用代码生成pdf文件,比如iText一类: 在后端抓取页面并生成pdf文件,比如pha ...

  8. 图书推荐《图解HTTP》

    作品简介 本书对互联网基盘——HTTP协议进行了全面系统的介绍.作者由HTTP协议的发展历史娓娓道来,严谨细致地剖析了HTTP协议的结构,列举诸多常见通信场景及实战案例,最后延伸到Web安全.最新技术 ...

  9. B+树的算法(java实现)

    定义 一颗m阶B+树满足以下几个条件: 1.除根节点外的节点的关键字个数最大为m-1,最小为m/2 2.除叶节点外的每个节点的孩子节点的数目为该节点关键字个数加一,这些孩子节点的的关键字的范围与父节点 ...

  10. linux线程绑定cpu

    函数介绍 #define __USE_GNU #include <sched.h> void CPU_ZERO(cpu_set_t *set); void CPU_SET(int cpu, ...