当前位置: 代码迷 >> 综合 >> Maximum Distributed Tree CodeForces - 1401D 树上dfs+贪心
  详细解决方案

Maximum Distributed Tree CodeForces - 1401D 树上dfs+贪心

热度:78   发布时间:2023-11-28 03:20:21.0

题目链接

题目大意

有一棵树 一共有n-1边 你需要给n-1边赋值 需要满足以下条件

1每个值大于0正整数

2所有值的1的数量最少

3所有值的乘积为k (k给出 k的素因数们也给出)

在满足以上条件的基础上

要求这个  值最大 ,f(u,v)代表是u和v之间的简单路径

 

题目思路

题目可转化为求每个边所经过的次数 然后进行贪心将pi值填进去

问题主要在于在这个公式下

如何求树上每个边经过的次数

在这个公式下任意两个点都有一次将两点之间的简单路径逐个次数++的运算

那么对于每一条边(u,v)的经过次数 只需要计算 这个边左节点的节点数量*右节点的节点数量

即sz[u]*sz[v]=sz[u]*(n-sz[u])

对于sz的计算用一次dfs即可 方式类似于求树深度和直径之类的

最后注意贪心

判断一下m与n-1数量关系

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
const int maxm=2e5+10;
const int mod=1e9+7;
int t,n,m;
int cnt=1;
int tot=0;
ll head[maxn*2];
ll p[maxn];
ll a[maxn];
ll sz[maxn*2];
struct xy
{ll next,to,dis;
}e[maxm*2];
void add(int u,int v,ll d)
{e[++cnt].dis=d;e[cnt].next=head[u];e[cnt].to=v;head[u]=cnt;
}
void init()
{cnt=1;tot=0;memset(head,0,sizeof(head));memset(e,0,sizeof(e));for(int i=0;i<=n;i++) {sz[i]=0;a[i]=0;p[i]=0;}
}
bool cmp(ll x,ll y)
{if(x>y)return 1;else return 0;
}
void dfs(int now,int fa)
{int u=now;sz[u]=1;for(int i=head[u];i;i=e[i].next){int v=e[i].to;if(v==fa)continue;dfs(v,u);sz[u]+=sz[v];a[++tot]=sz[v]*(n-sz[v]);}
}
int main()
{cin>>t;while(t--){cin>>n;init();int x,y;for(int i=1;i<=n-1;i++){cin>>x>>y;add(x,y,1);add(y,x,1);}dfs(1,0);cin>>m;for(int i=1;i<=m;i++){cin>>p[i];} sort(a+1,a+tot+1,cmp);sort(p+1,p+m+1,cmp);ll ans=0;if(m<=n-1){for(int i=1;i<=tot;i++){if(i<=m){ans=(ans+(p[i]%mod*a[i]%mod)%mod)%mod;}else {ans=(ans+a[i]%mod)%mod;}}}else {ll pos=1;for(int i=1;i<=m-n+2;i++){pos=(pos*p[i]%mod)%mod;//ans=(ans+(a[1]%mod*p[i]%mod)%mod)%mod;}ans=a[1]*pos%mod;ans%mod;for(int i=2;i<=tot;i++){ans=(ans+(a[i]%mod*p[m-n+i+1]%mod)%mod)%mod;}}cout<<ans%mod<<endl;}return 0;
}

  相关解决方案