CF 557C Arthur and Table(贪心)

刚读题想到用dp,思考一下发现dp并不是那么容易。然后脑补出来了贪心做法:枚举每一个长度 l 使得最终的稳定态是以 l 为最长腿,那么所有比 l 大的桌腿我们都要砍掉,然后所有 l 的都不砍,最后把比 l 小的若干个 d 比较小的砍掉之后使得 l 的个数大于其他桌腿的个数。

具体实现的时候,我们先把桌腿按照 l 升序排列,然后预处理出来cnt[i],first[i],两个个数组。其中cnt[i]表示桌腿长度为i的个数,first[i]表示长度为 i 的桌腿第一次出现在数列中的位置。然后枚举桌腿的长度,求出最小的花费即可。

枚举桌腿后求花费的时候我们需要找到区间前k小数。这里用d[i][j]数组预处理下。d[i][j]数组表示前 i 个桌腿 d 为 j 的个数,然后就可以o(dmax=200)的时间内找到前k小数。

#pragma warning(disable:4996)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
struct line{
	int l, d;
	bool operator<(const line&op)const{
		return l < op.l;
	}
};

line a[100005];
int cnt[100005] = { 0 };//标记l出现的个数
LL sum[100005] = { 0 };//d的前n项和
int first[100005] = { 0 };//l最早出现的位置
int d[100005][201] = { 0 };

int main(){
	int n; scanf("%d", &n);
	for (int i = 1; i <= n; i++){
		scanf("%d", &a[i].l);
		cnt[a[i].l]++;
	}
	for (int i = 1; i <= n; i++){
		scanf("%d", &a[i].d);
	}
	sort(a + 1, a + 1 + n);

	for (int i = 1; i <= n; i++){
		sum[i] = sum[i - 1] + a[i].d;
		if (first[a[i].l] == 0)first[a[i].l] = i;
		for (int j = 1; j < 201; j++){
			d[i][j] = d[i - 1][j];
		}
		d[i][a[i].d]++;
	}
	LL ans = 1000000000000LL;
	for (int i = 1; i <= 100000; i++){
		if (cnt[i]){
			int pos = first[i] + cnt[i] - 1;
			LL now = sum[n] - sum[pos];
			int qudiao = first[i] - cnt[i];
			if (qudiao > 0){
				for (int j = 1; j < 201; j++){
					if (qudiao >= d[first[i] - 1][j]){
						now += d[first[i] - 1][j] * j;
						qudiao -= d[first[i] - 1][j];
					}
					else{
						now += qudiao*j;
						break;
					}
				}
			}
			ans = min(ans, now);
		}
	}
	printf("%I64d\n", ans);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值