【LG4437】[HNOI/AHOI2018]排列
【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_{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]排列的更多相关文章
- [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_ ...
- BZOJ5289 HNOI/AHOI2018排列(贪心+堆)
题面描述的相当绕,其实就是如果ai=j,重排后ai要在aj之后.同时每个ai有附属属性wi,要求最大化重排后的Σiwi. 容易发现这事实上构成一张图,即由j向i连边.由于每个点入度为1或0,该图是基环 ...
- 【洛谷 P4437】 [HNOI/AHOI2018]排列(贪心,堆)
题目链接 如果\(j<=k,a_{p[j]}!=p[k]\)可以理解为如果\(a_{p[j]}=p[k]\),那么\(k\)一定要放在\(j\)前面,也就是\(a_j\)在\(j\)前面. 于是 ...
- BZOJ5289 & 洛谷4437:[HNOI/AHOI2018]排列——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=5289 https://www.luogu.org/problemnew/show/P4437 考虑 ...
- Poj2054 color a tree && [HNOI/AHOI2018]排列
https://zybuluo.com/ysner/note/1120723 题面 原题 某省选强化题 大致意思是给你一颗树,选父亲后才能选儿子. 每个点对答案的贡献为你在第几次选这个点 × 该点权值 ...
- luogu P4437 [HNOI/AHOI2018]排列
luogu 问题本质是把\(a_i\)作为\(i\)的父亲,然后如果有环就不合法,否则每次要取数,要满足取之前他的父亲都被取过(父亲为0可以直接取),求最大价值 贪心想法显然是要把权值大的尽量放在后面 ...
- 【题解】Luogu P4436 [HNOI/AHOI2018]游戏
原题传送门 \(n^2\)过百万在HNOI/AHOI2018中真的成功了qwqwq 先将没门分格的地方连起来,枚举每一个块,看向左向右最多能走多远,最坏复杂度\(O(n^2)\),但出题人竟然没卡(建 ...
随机推荐
- flash判断,及安装注意
使用下面方法判断flash版本 function flashChecker() { var hasFlash = 0; //是否安装了flash var flashVersion = 0; //fla ...
- (三十四)golang--接口
golang的多态特性主要体现在接口上: 主要优势:高内聚低耦合: package main import ( "fmt" ) type usb interface { start ...
- CentOS 下安装 Cmake 步骤
最近在虚拟机中的 CentOS 中安装 Cmake.把安装步骤记录在此. 什么是 Cmake CMake 是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程).他能够输出各 ...
- CodeForce 192D Demonstration
In the capital city of Berland, Bertown, demonstrations are against the recent election of the King ...
- Oracle数据库rownum用法集锦
Oracle中rownum可以用来限制查询 具体用法: 1.返回查询集合中的第1行 select * from tableName where rownum = 1 2.返回查询集合中的第2行 错误示 ...
- 什么是IDE(集成开发环境)?
实际开发中,除了编译器是必须的工具,我们往往还需要很多其他辅助软件,例如: 编辑器:用来编写代码,并且给代码着色,以方便阅读: 代码提示器:输入部分代码,即可提示全部代码,加速代码的编写过程: 调试器 ...
- python操作时间
一.问题背景 在对数据进行操作的时候我们总是会遇到数据类型是date类型的数据,这种数据会让我们在使用和操作的过程中遇到一些问题,比如int类型和date类型不对等,string类型和date类型不对 ...
- SkyWalking分布式链路追踪和监控-项目实战
微服务框架落地后,分布式部署架构带来的问题就会迅速凸显出来.服务之间的相互调用过程中,如果业务出现错误或者异常,如何快速定位问题?如何跟踪业务调用链路?如何分析解决业务瓶颈?本专栏将引入Skywalk ...
- Elasticsearch PUT 插入数据
{ "error": { "root_cause": [ { "type": "illegal_argument_exceptio ...
- Out,ref,params修饰符,可选参数,命名参数
out输出,在调用函数中声明,在被调用函数中赋值: ref在调用函数中赋值,后调用: params修饰符,static double CalculateAverage(params[] values) ...