Codeforces 1199C mp3(尺取)
题目大意
(懒得写了直接搬的学长的翻译)已知共有n个音符, 一共有K个音符强度。每种音符强度需要A=logK(向上取整)位用来存储。整体所需空间是\(N\times A\)位。例如十个音符、一共四种音符强度,则需要10*log4=20位存储。 但由于武学长的硬盘存储空间不足,我们需要选取一定范围的音符强度保持不变,小于该范围的修改为该范围的最小值,大于该范围修改为该范围的最大值。 但武学长是对音质极为注重,他希望你能提供一个程序,将音频压缩位最大I字节的文件并最小程度的修改音符数量。 提示:一个字节等于8位。
解题思路
显然,如果初始状态需要的空间小于\(8 \times I\)的话,就需要缩小音符的种类,既然所得的是一个连续的区间,那么就只要两种缩法,要么从头开始缩,要么从尾部开始缩。我们枚举左边界L,可以发现R是不断增大的,所以就可以通过尺取来解决问题,不过因为音符的强度范围问题,需要在尺取之前做一下离散化以方便尺取。
代码
const int maxn = 4e5+10;
int a[maxn], b[maxn], cnt[maxn], n, I;
ll solve(int x) {
if (x==1) return 0;
return ceil(log2l(x));
}
int main() {
scanf("%d%d",&n,&I);
for (int i = 0; i<n; ++i) {
scanf("%d",&a[i]);
b[i] = a[i];
}
sort(b,b+n);
int k = unique(b,b+n)-b;
for (int i = 0; i<n; ++i) {
a[i] = lower_bound(b,b+k,a[i])-b;
++cnt[a[i]];
}
int r = 0, ans = INF, sum = 0;
for (int i = 0; i<k; ++i) {
while(r<=k && solve(r-i+1)*n<=8LL*I) {
sum += cnt[r++];
ans = min(n-sum,ans);
}
sum -= cnt[i];
}
printf("%d\n",ans);
return 0;
}