洛谷 P4437 [HNOI/AHOI2018]排列(贪心+堆,思维题)
开始 WA ycx 的遗产(bushi
首先可以将题目转化为图论模型:\(\forall i\) 连边 \(a_i\to i\),然后求图的一个拓扑序 \(b_1,b_2,\dots b_n\) 使得 \(\sum\limits_{i=1}^niw_{b_i}\) 最小。显然如果原图出现环就 \(-1\) 了。否则原图一定是一棵森林。
然后我就在那儿想各种乱搞,包括但不限于 DP、贪心之类,然后都假掉了
我们知道有个东西叫排序不等式,它是说 \(\forall a_1\leq a_2\leq a_3\leq\dots\leq a_n,b_1\leq b_2\leq b_3\leq\dots\leq b_n\) 都有 \(\sum\limits_{i=1}^na_ib_i\geq\sum\limits_{i=1}^na_ib_{p_i}\geq\sum\limits_{i=1}^na_ib_{n-i+1}\),其中 \(p\) 为 \(1\sim n\) 的任意一个排列。
将排序不等式应用于此题。如果设 \(a_i=i\),\(b\) 为 \(w\) 排好序的结果可得理论最大值为 \(\sum\limits_{i=1}^nib_i\)。换句话说,假设使 \(w_i\) 取到最小值的 \(i\) 为 \(x\),那么我们肯定贪心地想把 \(x\) 放在前面,越靠前越好。
不过问题是,\(a_x\) 不一定等于 \(0\),也就是说 \(x\) 不一定有能力成为拓扑序的第一个元素。这时候该怎么办呢?我们不考虑现在,我们考虑未来。我们定义当前状态下的“可选集合”为满足 \(a_x=0\) 或者 \(a_x\) 已经被加入拓扑序的 \(x\) 的集合,也就是说可选集合内的元素都可以成为拓扑序中的下一个元素。考虑什么时候 \(x\) 能够进入可选集合。显然要当 \(a_x\) 已经被加入拓扑序之后。而根据之前的推论我们肯定希望 \(x\) 越靠前越好,也就是说一旦 \(a_x\) 被加入拓扑序,我们就令 \(x\) 为拓扑序中下一个元素,相当于将 \(a_x\) 与 \(x\) 捆绑在了一起。
P.S:如果你对为什么 \(x\) 越靠前越好的证明感兴趣的话,可以从这里往下看:
假设 \(a_x\) 是第 \(s\) 个加入拓扑序的,\(x\) 是第 \(t(t>s+1)\) 个加入拓扑序的,第 \(i\) 个加入拓扑序的元素为 \(b_{i}\),那么我们显然有代价为 \(\sum\limits_{i=1}^siw_{b_i}+\sum\limits_{i=1}^{t-s-1}(s+i)w_{b_{i+s}}+tw_x+\sum\limits_{i=t+1}^niw_{b_i}\)
而倘若我们将第 \(x\) 个元素加入拓扑序的时间提前到 \(s+1\),其他元素加入拓扑序的时间保持不变,那么代价变为 \(\sum\limits_{i=1}^siw_{b_i}+(s+1)w_x+\sum\limits_{i=1}^{t-s-1}(s+i+1)w_{b_i+s}+\sum\limits_{i=t+1}^niw_{b_i}\)
二者做差可得 \(\Delta=\sum\limits_{i=1}^{t-s-1}w_{b_i+s}-(t-s-1)w_x\)
根据 \(w_x\) 为 \(\min\{w_i\}\) 可知 \(\dfrac{\sum\limits_{i=1}^{t-s-1}w_{b_i+s}}{t-s-1}\geq w_x\),换句话说,任意 \(t-s-1\) 个 \(w_i\) 的平均值 \(\geq w_x\)。
故 \(\Delta\geq 0\)。而显然将第 \(x\) 个元素加入拓扑序的时间提前到 \(s+1\) 依旧合法。故我们选择 \(x\) 越靠前越好。
还有一个问题,就是经过若干次合并后树上的每一个元素都是一个合并序列,也就是若干个形如 \(t_1,t_2,\dots t_m\),其中 \(t_i\) 拓扑序下一个必须是 \(t_{i+1}\) 的序列。此时我们就要探究合并序列的大小关系,考虑两个序列 \(x_1,x_2,\dots x_p\) 和 \(y_1,y_2,\dots,y_q\) 合并的大小关系。
- 若 \(x\) 合并到 \(y\) 前面,\(W=\sum\limits_{i=1}^piw_{x_i}+\sum\limits_{i=1}^q(i+p)w_{y_i}\)
- 若 \(y\) 合并到 \(x\) 前面,\(W=\sum\limits_{i=1}^qiw_{y_i}+\sum\limits_{i=1}^p(i+q)w_{x_i}\)
二者做差可得 \(\Delta=-q\times\sum\limits_{i=1}^pw_{x_i}+p\times\sum\limits_{i=1}^qw_{y_i}\)
我们不妨假设 \(\Delta\geq 0\),不等号两边同除 \(pq\) 可得 \(-\dfrac{\sum\limits_{i=1}^pw_{x_i}}{p}+\dfrac{\sum\limits_{i=1}^qw_{y_i}}{q}\geq 0\)。
即 \(\dfrac{\sum\limits_{i=1}^qw_{y_i}}{q}\geq \dfrac{\sum\limits_{i=1}^pw_{x_i}}{p}\)
也就是说我们选择将平均值大的序列合并到平均值小的序列的后面。
用堆维护即可。
复杂度线性对数。
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
namespace fastio{
#define FILE_SIZE 1<<23
char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
inline void putc(char x){(*p3++=x);}
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
const int MAXN=5e5;
int n,a[MAXN+5],b[MAXN+5],vis[MAXN+5];
void dfs(int x){
if(!(vis[x]^2)) puts("-1"),exit(0);
if(!(vis[x]^1)) return;vis[x]=2;
if(a[x]) dfs(a[x]);vis[x]=1;
}
int f[MAXN+5],siz[MAXN+5];ll sum[MAXN+5],val[MAXN+5];
int getf(int x){return (!~f[x])?x:f[x]=getf(f[x]);}
void merge(int x,int y){
x=getf(x);y=getf(y);
f[y]=x;sum[x]+=sum[y];
val[x]+=val[y]+1ll*sum[y]*siz[x];
siz[x]+=siz[y];
// printf("merge %d %d %d %lld %lld\n",x,y,siz[x],sum[x],val[x]);
}
struct frac{
ll x,y;
frac(ll _x=0,ll _y=1):x(_x),y(_y){}
bool operator <(const frac &rhs) const{
return x*rhs.y<rhs.x*y;
}
};
set<pair<frac,int> > st;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
for(int i=1;i<=n;i++) dfs(i);f[0]=-1;
for(int i=1;i<=n;i++) f[i]=-1,siz[i]=1,sum[i]=val[i]=b[i];
for(int i=1;i<=n;i++) st.insert(mp(frac(b[i],1),i));
while(!st.empty()){
pair<frac,int> pp=*st.begin();st.erase(st.begin());
int id=pp.se,f1=getf(id),f2=getf(a[f1]);
if(f2) st.erase(st.find(mp(frac(sum[f2],siz[f2]),f2)));
merge(f2,f1);if(f2) st.insert(mp(frac(sum[f2],siz[f2]),f2));
} printf("%lld\n",val[0]);
return 0;
}
洛谷 P4437 [HNOI/AHOI2018]排列(贪心+堆,思维题)的更多相关文章
- [Bzoj5285][洛谷P4424][HNOI/AHOI2018]寻宝游戏(bitset)
P4424 [HNOI/AHOI2018]寻宝游戏 某大学每年都会有一次Mystery Hunt的活动,玩家需要根据设置的线索解谜,找到宝藏的位置,前一年获胜的队伍可以获得这一年出题的机会. 作为新生 ...
- [HNOI/AHOI2018]排列 贪心
题面 题解: 把题面的限制换成中文: 如果排在第k位的下标 = 排在第j位的值 ,那么k < j 换一个描述方式: 一个值为x的数要排在第x个数后面. 再换一个描述方式: \(fa[i] = a ...
- 洛谷P4438 [HNOI/AHOI2018]道路(dp)
题意 题目链接 Sol 每当出题人想起他出的HNOI 2018 Day2T3,他都会激动的拍打着轮椅 读题比做题用时长系列... \(f[i][a][b]\)表示从根到\(i\)的路径上,有\(a\) ...
- luogu P4437 [HNOI/AHOI2018]排列
luogu 问题本质是把\(a_i\)作为\(i\)的父亲,然后如果有环就不合法,否则每次要取数,要满足取之前他的父亲都被取过(父亲为0可以直接取),求最大价值 贪心想法显然是要把权值大的尽量放在后面 ...
- 洛谷P4425 [HNOI/AHOI2018]转盘(线段树)
题意 题目链接 Sol 首先猜一个结论:对于每次询问,枚举一个起点然后不断等到某个点出现时才走到下一个点一定是最优的. 证明不会,考场上拍了3w组没错应该就是对的吧... 首先把数组倍长一下方便枚举起 ...
- 洛谷P4424 [HNOI/AHOI2018]寻宝游戏(思维题)
题意 题目链接 Sol 神仙题Orz Orz zbq爆搜70.. 考虑"与"和"或"的性质 \(0 \& 0 = 0, 1 \& 0 = 0\) ...
- [洛谷P4436] HNOI/AHOI2018 游戏
问题描述 一次小G和小H在玩寻宝游戏,有n个房间排成一列,编号为1,2,...,n,相邻的房间之间都有一道门.其中一部分门上锁(因此需要有对应的钥匙才能开门),其余的门都能直接打开.现在小G告诉了小H ...
- 洛谷 P4426 - [HNOI/AHOI2018]毒瘤(虚树+dp)
题面传送门 神仙虚树题. 首先考虑最 trival 的情况:\(m=n-1\),也就是一棵树的情况.这个我相信刚学树形 \(dp\) 的都能够秒掉罢(确信).直接设 \(dp_{i,0/1}\) 在表 ...
- 【LG4437】[HNOI/AHOI2018]排列
[LG4437][HNOI/AHOI2018]排列 题面 洛谷 题解 题面里这个毒瘤的东西我们转化一下: 对于\(\forall k,j\),若\(p_k=a_{p_j}\),则\(k<j\). ...
随机推荐
- I-Base62
I - Base62 PS:一个任意进制转换的大数问题 传送门:Base62 短除法原理: 20(10进制) => 202(3进制) 20 = (2 * 3 ^ 2 + 0 * 3 ^ 1 + ...
- [对对子队]会议记录4.11(Scrum Meeting 2)
今天已完成的工作 何瑞 工作内容:完成指令的衔接:完成合成指南界面的制作:初步实现成本系统 相关issue:实现用户指令编辑系统的逻辑 马嘉 工作内容:完成游戏内暂停界面 相关issu ...
- Machine learning (6-Logistic Regression)
1.Classification However, 2.Hypothesis Representation Python code: import numpy as np def sigmoid(z) ...
- 常用JAVA API :String 、StringBuilder、StringBuffer的常用方法和区别
摘要 本文将介绍String.StringBuilder类的常用方法. 在java中String类不可变的,创建一个String对象后不能更改它的值.所以如果需要对原字符串进行一些改动操作,就需要用S ...
- 第一个只出现一次字符的位置 牛客网 剑指Offer
第一个只出现一次字符的位置 牛客网 剑指Offer 题目描述 在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 ...
- WPF实现统计图
WPF开发者QQ群: 340500857 | 微信群 -> 进入公众号主页 加入组织 前言 有小伙伴提出需要实现统计图. 由于在WPF中没有现成的统计图控件,所以我们自己实现一个. PS:有更 ...
- cesium制作自己的骑行轨迹
制作自己的骑行轨迹 马上国庆节了,计划骑车回家,突然想到把所有的骑行线路汇总一下,无奈码表和APP不支持这样的操作,出于职业病,在此操作一下. 我用的是黑鸟码表,可以导出fit运动轨迹,但是fit还需 ...
- mongoDB 的一般使用
理解 mongodb 也是nosql 的一种.他的数据存储类型是一种和json格式比较像的数据类型,可以看作就是json. mongodb 里的数据库都是一个单独的库.一般需要用的库都会设置自己的us ...
- redis 的主从模式哨兵模式
原理理解 1,哨兵的作用就是检测redis主服务的状态,如果主服务器挂了,从服务就自动切换为主服务器,变为master.哨兵是一个独立的进程,作为进程,它会独立运行.其原理是哨兵通过发送命令,等待Re ...
- 使用vsftpd 搭建ftp服务
ftp 基础服务器基础知识 ftp有三种登录方式.匿名登录(所有用户).本地用户.虚拟用户(guest). FTP工作模式 主动模式:服务端从20端口主动向客户端发起链接. 控制端口21:数据传输端口 ...