D. GCD and MST(MST&双指针)

按照 k r u s k a l kruskal kruskal的思路,先对 a i a_i ai排序。

然后贪心将 a i a_i ai左右扩展至最大是最优的,同时维护一个标记数组 v i s [ i ] vis[i] vis[i]

表示位置 i i i向右连有一条边。当 w ≥ p w\ge p wp直接 b r e a k break break,因为用 p p p此时更优。

时间复杂度: O ( n l o g n + n ) O(nlogn+n) O(nlogn+n)

// Problem: D. GCD and MST
// Contest: Codeforces - Divide by Zero 2021 and Codeforces Round #714 (Div. 2)
// URL: https://codeforces.ml/problemset/problem/1513/D
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// Date: 2021-08-25 17:59:49
// --------by Herio--------

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=2e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define IOS ios::sync_with_stdio(false),cin.tie(0) 
void Print(int *a,int n){
	for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\n",a[n]); 
}
int t,n,p,val[N];
PII a[N];
bitset<N>vis;
int main(){
	scanf("%d",&t);while(t--){
		scanf("%d%d",&n,&p);
		rep(i,1,n) scanf("%d",&val[i]),a[i]={val[i],i},vis[i]=0;
		sort(a+1,a+n+1);
		ll s=0;
		int c=0;
		rep(i,1,n){
			int x=a[i].fi,y=a[i].se;
			if(x>=p) break;
			for(int j=y-1;j>0&&!vis[j]&&val[j]%x==0;j--) c++,vis[j]=1,s+=x;
			for(int j=y+1;j<=n&&!vis[j-1]&&val[j]%x==0;j++) c++,vis[j-1]=1,s+=x;
		}
		s+=1LL*(n-1-c)*p;
		printf("%lld\n",s);
	}
	return 0;
}