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;
}
posted @ 2020-07-03 22:25  shuitiangong  阅读(201)  评论(0编辑  收藏  举报