题解:P10455 Genius Acm
P10455 Solution
做法:贪心,倍增,归并思想
题意
给定
设一组 CPU 的性能为
思路
Part 1. 贪心
第一眼我们知道测试用的 CPU 既然是随机抽,那么我们要使得最大的 SPD 都不超过
设有四数
则有两种取数方式:
则第一种方式的 SPD 为
两式相减,得:
由于
即我们要使题目中最大的
Part 2. 倍增
根据题目数据,肯定是不能二分的,因为最坏情况下需要进行
那么可以用倍增平替掉(什么是倍增?)。朴素思想就是倍增模版,用变量
时间复杂度
Part 3. 归并思想优化
归并立大功。
发现在求 SPD 的函数中,每次都要将当前数组排一遍序,时间开销较大,所以考虑使用归并排序的思想。
增加一个变量
记得在符合条件后更新用来排序的数组并且不管怎样都要更新
时间复杂度
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 5e5 + 10;
int n, m, k, t, p[N], m1[N], m2[N];
int RPD (int a, int b) { return a - b; }
bool check (int s, int mid, int e)
{
for (int i = mid; i < e; i ++) m1[i] = p[i];
sort (m1 + mid, m1 + e); //只排序[mid,e)
int lp = s, rp = mid, idx = 0, res = 0;
while (lp < mid && rp < e) //归并
{
if (m1[lp] <= m1[rp]) m2[idx ++] = m1[lp ++];
else m2[idx ++] = m1[rp ++];
}
while (lp < mid) m2[idx ++] = m1[lp ++];
while (rp < e) m2[idx ++] = m1[rp ++];
for (int i = 0; i < m && i < idx; i ++, idx --)
res += pow (RPD (m2[i], m2[idx - 1]), 2); //贪心求 SPD
return res <= k;
}
signed main ()
{
scanf ("%lld", &t);
while (t --)
{
scanf ("%lld%lld%lld", &n, &m, &k);
for (int i = 0; i < n; i ++) scanf ("%lld", p + i);
int stt = 0, end = 0, cnt = 0;
while (end < n)
{
int add = 1;
while (add > 0)
{
if (end + add <= n && check (stt, end, end + add))
{
end += add, add <<= 1;
if (end >= n) break;
for (int i = stt; i < end + add; i ++)
m1[i] = m2[i - stt]; //更新用来排序的数组
}
else add >>= 1;
}
cnt ++, stt = end; //更新起始位置
}
printf ("%lld\n", cnt);
}
return 0;
}
写在最后
还是那句话,归并立大功。
谢谢观看!