CF1630B题解
题解思路:
假设我们有若干个长为
有
我们至少要分成
每组都要满足
那么每组若只多一个,那么
所以一组里不满足的就有
所以满足的条件就是
你选的数
那么你的值域区间就是
排完序之后,遍历一下,你就能知道他的最小的值域区间是多少。
但是知道了最小的值域我们还要构造一个区间的分开方式
我们回到原序列,若有一个在所选区间的数,就让计数器
若不在值域的数,那么计数器
那么计数器
最后直接输出左右端点就可以了。
AC CODE:
#include <algorithm>
#include <iostream>
#include <vector>
#include <cstdio>
using namespace std;
const int N = 200010;
int n;
int cnt;
int tot , k;
int a[N] , b[N];
int l[N] , r[N];
int ansl , ansr;
vector <int> p[N];
void solve() {
scanf ("%d%d" , &n , &k);
tot = 0;
int len = (n + k + 1) / 2;//计算一个区间的长度
for (int i = 1; i <= n; i++) {
scanf ("%d" , &a[i]);
b[i] = a[i];//b保存的是排序后的数组
}
sort(b + 1, b + 1 + n);//排序
ansl = 1, ansr = len;
for (int i = 2; i + len - 1 <= n; i++)
if (b[i + len - 1] - b[i] < b[ansr] - b[ansl])
ansl = i, ansr = i + len - 1;
for (int i = 1, u = 1; i <= k; u++, i++) {
l[i] = u;
for (int cnt = 0;; u++) {
if (a[u] >= b[ansl] && a[u] <= b[ansr]) //若满足条件
cnt++;//计数器++
else //否则
cnt--;//计数器--
if (cnt > 0) {//只要大于0,就是
r[i] = u;
break;
}
}
}
r[k] = n;
printf ("%d %d\n" , b[ansl] , b[ansr]);
for (int i = 1; i <= k; i++) //输出
printf ("%d %d\n" , l[i] , r[i]);
}
int main() {
int T;
scanf ("%d" , &T);
while (T --)
solve();
return 0;
}
码字不易,求赞!