Codeforces Round #714 (Div. 2) D. GCD and MST

Divide by Zero 2021 and Codeforces Round #714 (Div. 2) D. GCD and MST

D. GCD and MST


题意

给定一个大小为n(n>2)的正整数数组a,给定一个正整数p。如果gcd(ai,ai+1,ai+2,…,aj)=min(ai,ai+1,ai+2,…,aj),那么就可以在i与j之间建立一条权值为min(ai,ai+1,ai+2,…,aj)或p的边,如果不相等则可以建立一条只能建立权值为p的边。问:该图的最小生成树的权值和是多少?


思路

该题的思路类似kruskal求最小生成树的过程,也就是每次去寻找权值最小的边,判断将该边加入后是否形成了环,如果没有则将该边加入。
根据这个思想,这个题就可以简化为如何去寻找最小的边的问题,解决办法就是,将a数组按值进行从小到大排序,对于排列后的数组进行遍历,①如果当前值大于p说明通过它建的边一定大于p,直接退出循环;②如果当前值小于等于p,那么从该值在未排序的a所在的位置x,分别向左,向右判断(判断条件见代码),并把满足条件的标记,将权值加入答案;③对于已经标记过的点直接跳过。
最后将还未加入的点通过建立权值为p的边将其加入。


AC代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> P;
ll aa[200010],vis[200010];
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		vector<P> bb;
		memset(vis,0,sizeof(vis));
		ll n,p;
		cin>>n>>p;
		for(int i=1;i<=n;i++)
		{
			cin>>aa[i];
			bb.push_back(P(aa[i],i));
		}
		ll sum=n-1,ans=0;
		sort(bb.begin(),bb.end());
		for(int i=0;i<n;i++)
		{
			if(bb[i].first>p) break;
			ll x=bb[i].second;
			if(vis[x]) continue;
			ll l=x,r=x;
			while(l>1&&!vis[l]&&aa[l-1]%aa[x]==0) l--;
			while(r<n&&!vis[r]&&aa[r+1]%aa[x]==0) r++;
			ans+=aa[x]*(r-l);
			sum-=r-l;
			for(ll j=l;j<=r;j++)
				vis[j]=1;
		}
		ans+=p*sum;
		cout<<ans<<endl;
	}
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值