Bzoj5289:[Hnoi2018]排列

[HNOI/AHOI2018]排列

题目看这里

题解

%20 搜索枚举全排列
%40 给好的搜索??随机化一下吧,人品可以的应该能拿到吧。
%60 距离正解差了一个log?发现是树然后暴力枚举???
%80 都有这个分数了,为什么不拿100???

正解:
很显然的是对于\(a[i]\),我们直接把\(i\)\(a[i]\)连一条边
没有0时,无解,听说还要判环
n+1个点,n条边,连同==>树。
然后原题变成:
给出一棵以 0 为根的有根树,需要为非 0 顶点标号 1∼n ,并且满足父亲比自己先标号。每个节点有点权,树的价值为点权乘标号的和。求树最大的价值。
一个很显然的贪心就是如果当前节点权值很小,且它的父亲被选取了,那么优先给它标号。

NaVi_Awson爷这里给出了很好的解释,以下原话照搬

考虑如果 \(u\) 有父亲,显然当他的父亲被选之后马上就会选 \(u\) ,也就是说父子间的编号一定是相邻的。我们可以将 \(u\) 的答案并在他的父亲中。

同样的,对于两个不同的“块”,也是如此。

考虑一个长度为 \(l1\) 的序列 \(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}\)

也就是平均权值小的放前面答案会更优。

Code

但是不吸氧要TLEqwq。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#define ll long long 
using namespace std;
const ll N=5e5+5;
ll n,a[N],fa[N],sz[N];
ll w[N],flag=1;
struct node{
	ll id,vi,sz;
	node(ll _id=0,ll _vi=0,ll _sz=0){id=_id,vi=_vi,sz=_sz;}
	bool operator < (const node &b) const {return vi*b.sz>b.vi*sz;}
};
priority_queue<node>q;
ll read(){
	ll x=0,w=1;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*w;
}
ll find(ll x){return x==fa[x]?x:fa[x]=find(fa[x]);}
int main(){
	n=read();
	for(ll i=1;i<=n;i++){
		a[i]=read();if(a[i]==0)flag=0;
	}if(flag){cout<<"-1"<<endl;return 0;}
	ll ans=0;ll len=0;
	for(ll i=1;i<=n;i++){
		w[i]=read();
		q.push(node(i,w[i],1));
		sz[i]=1;ans+=w[i];
	}
	for(ll i=0;i<=n;i++)fa[i]=i;
	while(!q.empty()){
		node t=q.top();q.pop();
		if(sz[t.id]!=t.sz)continue;
		if(find(a[t.id])==0){
			ans+=len*w[t.id];fa[t.id]=0;len+=t.sz;
		}
		else {
			ll 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]));
		}
	}cout<<ans<<endl;
	return 0;
}
posted @ 2019-02-16 17:02  Epiphyllum_thief  阅读(122)  评论(0编辑  收藏  举报