【ACM】HDU 6533 Build Tree(2019湘潭邀请赛B题)贪心

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6533

You need to construct a full n-ary tree(n叉树) with m layers.All the edges in this tree have a weight.But this weight cannot be chosen arbitrarily you can only choose from set S,the size of S is k,each element in the set can only be used once.Node 0 is the root of tree.

We use d(i) for the distance from root to node i.Our goal is to minimize the following expression:

min∑i=0Nd(i)




Please find the minimum value of this expression and output it.Because it may be a big number,you should output the answer modul p.

题意是说给出一个m层的满n叉数和一个大小为k的集合S,从S中不重复的选择值作为边权,使得每一个结点到根节点的总权值最小。输出总权值模p。

比赛的时候以为根节点不算一层,再加上题意看错了,一直陷在只有3条边,但是集合S里有5个值里面,没有做出来。实际上这道题是一个很简单的贪心。越低层的边使用的次数越少,就安排大的权值,越上层的边使用的次数越多,就安排小的权值。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
long long weight[maxn],ans[maxn],st[maxn];
void li(long long x)
{
	st[0]=1;
	for(int i=1;i<=60;i++)
	{
		if(st[i-1]*x<1e15)
			st[i]=st[i-1]*x;
	}
}
long long quickpow(long long res,long long ti)
{
	long long ans=1;
	while(ti)
	{
		if(ti&1)
			ans*=res;
		res*=res;
		ti>>=1;
	}
	return ans;
}
int main()
{
    //freopen("in.txt","r",stdin);
	long long k,m,n,p;
	while(~scanf("%lld%lld%lld%lld",&k,&m,&n,&p))
	{
		memset(ans,0,sizeof(ans));
		li(n);
//		for(int i=0;i<10;i++)
//            printf("%d %lld\n",i,st[i]);
		for(int i=0;i<k;i++)
			scanf("%lld",&weight[i]);
		sort(weight,weight+k);
		long long sum=1LL*(long long)(quickpow(n,m)-1)*1.0/(n-1);
		//printf("%lld\n",sum);
		int pos=1,co=0;
		for(int i=0;i<sum-1;i++)
		{
			if(co<st[pos])
			{
				ans[i]=1LL*(quickpow(n,m-pos)-1)*1.0/(n-1);
				//printf("%lld\n",ans[i]);
				co++;
			}
			if(co==st[pos])
			{
				pos++;
				co=0;
			}

		}
		long long res=0;
		for(int i=0;i<sum-1;i++)
			res=(res+weight[i]*ans[i]%p)%p;
		printf("%lld\n",res);
	}
	return 0;
}

下次加油!

猜你喜欢

转载自blog.csdn.net/qq_41279172/article/details/90613806