题目链接
题意:给定一个数组
{
a
1
,
a
2
,
.
.
.
,
a
n
}
\{a_1,a_2,...,a_n\}
{a1,a2,...,an},正整数
p
p
p和连边方式:
1.若存在
i
,
j
(
1
≤
i
,
j
≤
n
)
i,j(1\le i,j \le n)
i,j(1≤i,j≤n),
g
c
d
(
a
i
,
a
i
+
1
,
a
i
+
2
,
…
,
a
j
)
=
m
i
n
(
a
i
,
a
i
+
1
,
a
i
+
2
,
…
,
a
j
)
gcd(a_i, a_{i+1}, a_{i+2}, \dots, a_{j}) = min(a_i, a_{i+1}, a_{i+2}, \dots, a_j)
gcd(ai,ai+1,ai+2,…,aj)=min(ai,ai+1,ai+2,…,aj),在
i
,
j
i,j
i,j之间连一条权重为
m
i
n
(
a
i
,
a
i
+
1
,
a
i
+
2
,
…
,
a
j
)
min(a_i, a_{i+1}, a_{i+2}, \dots, a_j)
min(ai,ai+1,ai+2,…,aj)的边。
2.在所有
i
,
i
+
1
i,i+1
i,i+1之间连边,权重为
p
p
p
求最小生成树的权重
思路:
如果一段序列满足
g
c
d
(
a
i
,
a
i
+
1
,
a
i
+
2
,
…
,
a
j
)
=
m
i
n
(
a
i
,
a
i
+
1
,
a
i
+
2
,
…
,
a
j
)
gcd(a_i, a_{i+1}, a_{i+2}, \dots, a_{j}) = min(a_i, a_{i+1}, a_{i+2}, \dots, a_j)
gcd(ai,ai+1,ai+2,…,aj)=min(ai,ai+1,ai+2,…,aj),则所有数都是最小值的倍数。那么我们只要按照数值大小从小到大遍历数组,对于当前值
a
p
o
s
a_{pos}
apos,把它当成具有上述序列性质的序列中的最小值,往两边扩展,只要是
a
p
o
s
a_{pos}
apos的倍数都和
a
p
o
s
a_{pos}
apos连边,如果
a
p
o
s
<
p
a_{pos}<p
apos<p则在最后的最小生成树里用这条边去换一条权重为
p
p
p的边,整个过程中用
v
i
s
[
i
]
vis[i]
vis[i]来标记
[
i
,
i
+
1
]
[i,i+1]
[i,i+1]之间的边是否被替换。
AC代码:
#include <bits/stdc++.h>
#define rep(i, x, y) for (int i = x; i < y; i++)
#define per(i, x, y) for (int i = x; i >= y; i--)
#define ll long long
using namespace std;
inline int read() {
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
const int maxn = 2e5 + 10;
/***************main****************/
ll T = 1;
ll m, n;
ll a[maxn], vis[maxn];
vector<pair<ll, ll>> ma;
int main() {
T = read();
while (T--) {
n = read();
m = read();
ma.clear();
rep(i, 0, n) {
a[i] = read();
ma.push_back({a[i], i});
vis[i] = 0;
}
ll ans = m * (n - 1);
sort(ma.begin(), ma.end());
for (int i = 0; i < n; i++) {
ll pos = ma[i].second;
if (vis[pos]) continue;
for (int j = pos + 1; j < n; j++) {
if (vis[j - 1] || a[j] % a[pos] != 0) break;
vis[j - 1] = 1;
if (a[pos] < m) ans += a[pos] - m;
}
for (int j = pos - 1; j >= 0; j--) {
if (vis[j] || a[j] % a[pos] != 0) break;
vis[j] = 1;
if (a[pos] < m) ans += a[pos] - m;
}
}
cout << ans << endl;
}
return 0;
}