111211121212222322232323333433343434444444444444
【题解】CF1891E - Brukhovich and Exams
https://www.luogu.com.cn/problem/CF1891E
我们考虑把区间分段:若两个相邻的数不互素,中间分开;若两个相邻的数中有且仅有一个
首先考虑无
接着考虑全
- 如果两端都非
1 或n ,那么有len+1 对相邻数。可以通过len-1 次操作每次答案减少1 ,最后一次操作答案减少2 。 - 如果有一段为
1 或n ,那么从更靠中间的点的那端开始,len 次操作每次答案减少1 。 - 否则就是
1\sim n 全部都是1 ,易得答案是n-k ,特判即可。
然后现在会有若干种操作:减
贪心地操作即可。
//CF1891E
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int T, n, k, a[N], ot[N], ans[N];
int main(){
scanf("%d", &T);
while(T--){
scanf("%d%d", &n, &k);
bool flg = true;
for(int i = 1; i <= n; ++ i){
scanf("%d", &a[i]);
if(a[i] != 1){
flg = false;
}
}
if(flg){
printf("%d\n", n - k);
continue;
}
int le = 1, two = 0, one = 0, tp = 0;
ans[0] = 0;
for(int i = 1; i <= n; ++ i){
if(i != 1 && __gcd(a[i-1], a[i]) == 1){
++ ans[0];
}
if(a[i] == 1 && a[i+1] != 1){
int len = i - le + 1;
if(le == 1 || i == n){
one += len;
} else {
ot[++tp] = len;
}
le = i + 1;
} else if(__gcd(a[i], a[i+1]) != 1 || (a[i+1] == 1 && a[i] != 1)){
int len = i - le;
two += len / 2;
one += len % 2;
le = i + 1;
}
}
sort(ot + 1, ot + tp + 1);
for(int i = 1; i <= two; ++ i){
ans[i] = ans[i-1] - 2;
}
int ps = two;
for(int i = 1; i <= tp; ++ i){
for(int j = 1; j < ot[i]; ++ j){
ans[ps+1] = ans[ps] - 1;
++ ps;
}
ans[ps+1] = ans[ps] - 2;
++ ps;
}
for(int i = 1; i <= one; ++ i){
ans[ps+i] = ans[ps+i-1] - 1;
}
printf("%d\n", ans[k]);
for(int i = 0; i <= n; ++ i){
ans[i] = 0;
ot[i] = 0;
a[i] = 0;
}
}
return 0;
}