codeforces-1198A MP3

codeforces-1198A

题意

给出一个大小为 n 的数组,和一个整数 I ;
大小为 n 的数组,如果数组中不同数值的个数为K,则需要 nk 位来装这些数,
你可以进行一个操作,选择一个数值区间 [ L ,R ] 把大于 R 的数变成 R ,小于 L 的数变成 L ;给出的整数 I 代表字节数,一个字节8个位;问如果要使这个的数组可以被 I 字节装下,至少有几个数会被改变。

思路

通过给出了字节的大小,可以倒推到该字节数下装 n 个数,不同数值的最大值,即

K = 2 ^ [ (8.0 * I) / (1.0 * n) ]

因为如果要改变的数最小,必定不同数值的个数要尽可能的大。
因为改变数的操作是连续的一个区间,所以把数组从小到大排序;计算不同数值的数量,用 cnt 数组记录小于等于每种数值的个数总和,且升序排列(前缀和数组),最后遍历的 K 种连续的数值的数量总和取最大值,即取剩余数值数量总和的最小值。

代码

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
 
int a[400100], c[400100];
 
int main(){
	ll n, I;
	scanf("%lld%lld", &n, &I);
	for(int i = 0; i < n; i++){
		scanf("%lld", &a[i]);
	}
	sort(a, a + n);
	int K = 1, q = 1;
	for(int i = 0; i < n; i++){
		if(a[i] != a[i + 1]){
			c[K] = c[K - 1] + q;
			q = 1;
			K++;
		}
		else{
			q++;
		}
	}
	int pK = (8.0 * I) / (1.0 * n);
	if(pK > 19) pK = n;
	else pK = 1 << pK;
	if(pK >= K){
		printf("0\n");
	}
	else{
		int ans = 0x3f3f3f3f;
		for(int i = 1; i + pK - 1 < K; i++){
			int r = i + pK - 1;
			ans = min(ans, n - c[r] + c[i - 1]);
		}
		printf("%d\n", ans);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值