题解 CF1198A 【MP3】

wenge

2019-08-03 21:54:46

Solution

### 题目翻译: 一种保存音频的方式是保存声音在各个时刻的强度。在每个时刻,声音的强度是一个非负整数。所以我们可以把声音用包含 $n$ 个非负整数的一个数组表示。 如果在数组中恰有 $K$ 个不同值,我们需要 $k=\lceil \log_2 K\rceil$ 比特的空间存储每一个值。这需要 $nk$ 比特的空间去存储整个音频文件。 为了减少空间花费,我们需要压缩一下。一个常用的方法是减少可能的强度值的数量。我们选择两个整数 $l\leq r$,然后所有强度值将会按照如下的方式改变:如果这个强度值在区间$[l,r]$中,不对其做任何改变。如果强度值小于$l$,我们把它改成$l$;如果强度值大于$r$,我们把它改成$r$。你可以看到,很多低的强度值和高的强度值被舍弃了。 你的任务是进行这个压缩操作,使得文件能够装进一个大小为$I$字节的磁盘,并且使数组中改变的元素数量最少。 众所周知,1字节=8比特。 $k=\lceil \log_2 K\rceil$是最小的满足$K\leq 2^k$的整数。特别地,如果$K=1$,则$k=0$。 输入格式: 第一行,两个整数$n,I\ ( 1 \le n \le 4 \cdot 10^{5},1 \le I \le 10^{8})$,表示数组的长度和磁盘的空间(单位为字节)。 第二行,$n$个整数$a_i(0 \le a_{i} \le 10^{9})$,表示音频文件的数组。 输出格式: 一个整数,表示数组中改变的元素数量的最小值。 ### 题解: 我们先计算出磁盘能容纳的不同值的数量。 如果磁盘的空间(单位为字节)是$I$,那么磁盘的空间(单位为比特)就是$8I$。那么$k\leq \lfloor \frac{8I}{n}\rfloor$。所以可以得到的结论是$K\leq 2^k$。所以按照上述方法把$K$的最大值算出来就可以。 但是当$I$很大的时候$K$会是一个巨大的数字。但是$n\leq400000$,所以可以给$K$设一个上限,在实际计算中也不会用到那么大的$K$值。 我们先把数组排序一下。而题目要求可以等价于在排序后的数组找一个区间,使得其包含不同元素数不超过$K$个,且长度最大,输出不在区间中的元素个数。 可以维护一个队列来记录区间。我用了简单的离散化,简化了取不同值元素个数的方法。 AC代码: ```cpp #include <iostream> #include <cmath> #include <algorithm> #include <cstring> #include <queue> // using namespace std; typedef long long ll; #define clr(a,b) memset(a,b,sizeof(a)); ll n,m,x,y,ans; int a[400005]; int b[400005]; int main(){ //ios::sync_with_stdio(false); //cin.tie(0); ll K=1,k; cin>>n>>m; m*=8; k=m/n; while(k--&&K<=9999999999ll)K*=2; for(int i=1;i<=n;i++){ cin>>a[i]; } sort(a+1,a+n+1); for(int i=1;i<=n;i++){ b[i]=b[i-1]+(a[i]!=a[i-1]); } ans=0; deque<int> q; for(int i=1;i<=n;i++){ q.push_back(b[i]); while(b[i]-q.front()>=K)q.pop_front(); ans=max(ans,(ll)q.size()); } cout<<n-ans; return 0; } ```