【GDOI2022PJD1T3 流水线】题解

D1T3 流水线

题目

在计算机组成原理这门课中,小明的老师布置了实现 CPU 流水线的作业。小明打算设计出一个效率最高的流水线。简单来说,流水线就是将 CPU 分成若干个任务模块,而一个模块又可以继续划分成更小的模块,小模块可以划分成更小的小小模块......根据常识我们知道把一个任务划分后,每一个部分的代价会变少,但是可能会产生额外的代价。所以小明希望你帮助他解决这个问题。

我们可以用一棵以 1 为根的有根树来描述模块之间的关系,每个节点是一个模块,每个节点的点权对应着该模块的时间代价。每一个非叶子节点可以划分成该节点的儿子节点对应的模块。

每个模块都有一定的时间代价,而流水线最后的效率我们可以用划分的模块数乘上模块中时间代价最大的一个来表示,时间代价越小,流水线的效率越高。也就是说,假如小明最后把 CPU 划分为了 \(m\) 个模块,每个模块的代价为 \(w_1, w_2, \dots, w_m\),则总代价为 \(m \times \max(w_1, w_2, \dots, w_m)\)。另外,我们认为根节点对应的模块不往下划分模块也是一种合法的方案。

请你帮小明找到效率最高的流水线设计方案吧

思路

假设我们的枚举方案顺序是从根接待你开始自上而下。

我们现在有一种方案,其最大值为 \(x\),模块个数为 \(y\)

我们现在要向下走,把某个点变成其儿子节点。

在这过程中,显然, \(m\) 一定不会变小

那么要使结果反而变小,我们就要从 \(\max(w_1, w_2, \dots, w_m)\) 入手,使这个变小。

我们把当前的最大值 \(w_i\) 拿出来,变成其儿子节点,这样就会使 \(\max(w_1, w_2, \dots, w_m)\) 有机会变小,才能使结果反而小。

整个过程我们可以从根节点开始,用优先队列维护最大值即可。

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){int f=1,x=0;char ch=getchar();while(ch<'0'||
ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define N 200010
//#define M
//#define mo
struct node
{
	int x, y; 
	bool operator <(const node &A) const
	{
		return y<A.y; 
	}
}p; 
int n, m, i, j, k, T;
vector<int>v[N]; 
int w[N], f[N], c[N], ans; 
priority_queue<node>q; 
//priority_queue<node>q; 

signed main()
{
	
	n=read(); 
	for(i=1; i<=n; ++i) w[i]=read(); 
	for(i=2; i<=n; ++i) 
	{
		f[i]=read(); c[f[i]]=1; 
//		printf("%lld\n", f[i]); 
		v[f[i]].push_back(i); 
	} 
	p.x=1; p.y=w[1]; q.push(p); ans=w[1]; 
	while(!q.empty())
	{
		p=q.top(); q.pop(); 
//		printf("%lld\n", p.x); 
		if(!c[k=p.x]) return printf("%lld\n", ans), 0; 
		for(i=0; i<v[k].size(); ++i) 
		{
			p.x=v[k][i]; p.y=w[v[k][i]]; 
			q.push(p); 
		}
		ans=min(ans, (int)q.top().y*(int)q.size() ); 
	}
	return 0;
}

总结

这道题是一道挺妙的思维题,题目的关键条件在于 \(w_i\leqslant w_{f_i}\)

抓住这个关键条件,我们可以发现答案的两个变量的变化关系,然后用优先队列维护。

对于这类式子含最大最小值的题目,可以考虑优先队列。

对于式子里有多个影响因素,可以考虑每个影响因素的变化。

同时也要注意观察题目不起眼的特殊条件。

posted @ 2022-04-22 17:33  zhangtingxi  阅读(48)  评论(0编辑  收藏  举报