ABC 216 补题 E(二分+大根堆模拟

D - Pair of Balls
模拟
开一个 i d id id 数组, i d [ x ] [ 0 ] id[x][0] id[x][0] i d [ x ] [ 1 ] id[x][1] id[x][1] 表示编号为 x x x 的球所在的桶的编号,每消除一对球,就把球的编号 p u s h push push 进队列,通过球的编号找到需要更新的桶的编号

#include<bits/stdc++.h>
#define ll long long
#define _ 0
using namespace std;
const int maxn = 2e5 + 9;
ll n, m, x, y;
struct node
{
	vector <int> v;
	int pos;
}a[maxn];
vector <int> id[maxn];
queue <int> q;
int ans, now;
void work()
{
	cin >> n >> m;
	for(int i = 1; i <= m; ++i)
	{
		int k;cin >> k;
		for(int j = 1; j <= k; ++j)
		{
			int p;cin >> p;a[i].v.push_back(p);
			if(j == 1) id[p].push_back(i);
			if(id[p].size() == 2) q.push(p);
		}
	}
	while(!q.empty())
	{
		now =  q.front(); q.pop();
		ans += 2;
		int x = id[now][0];
		++a[x].pos;   
		if(a[x].pos < a[x].v.size())
		{
			int p = a[x].v[a[x].pos];
			id[p].push_back(x);
			if(id[p].size() == 2) q.push(p);
		} 
		int y = id[now][1];
		++a[y].pos;
		if(a[y].pos < a[y].v.size())
		{
			int p = a[y].v[a[y].pos];
			id[p].push_back(y);
			if(id[p].size() == 2) q.push(p);
		}
	}
	if(ans == 2 * n) cout << "Yes\n";
	else cout << "No\n";
}

int main()
{
	ios::sync_with_stdio(0);
	work();
	return ~~(0^_^0);
}

E - Amusement Park

先二分找到最小的 x x x,使得 > x >x >x 的数最后减到 x x x
然后直接用大根堆模拟,来暴力选取后面的数,因为去掉上面的数之后,至多只剩下 n n n 轮选择,所以复杂度是对的
只剩下不超过 n n n 轮的原因:如果最后剩下的次数超过 n n n,那么二分时的 m i d mid mid 可以再次左移,使得现在的 x − 1 x-1 x1,这与二分已经结束矛盾。

#include<bits/stdc++.h>
#define ll long long
#define _ 0
using namespace std;
const int maxn = 2e5 + 9;
ll n, m, k;
ll a[maxn];
bool check(ll mid)
{
	ll sum = 0;
	for(int i = 1; i <= n; ++i)	if(a[i] >= mid) 
	sum += a[i] - mid;
	return sum <= k;
}
ll get()
{
	ll l = 0, r = 0;
	for(int i = 1; i <= n; ++i) r = max(r, a[i]);
	while(l < r)
	{
		ll mid = (l + r) / 2;
		if(check(mid)) r = mid;
		else l = mid + 1;
	}
	return l;
}
void work()
{
	cin >> n >> k;
	for(int i = 1; i <= n; ++i)	cin >> a[i];
	ll lim = get(), ans = 0, num = 0;
	for(int i = 1; i <= n; ++i) if(a[i] >= lim)
	{
		num += a[i] - lim;
		ans += (a[i] - lim) * (a[i] + lim + 1) / 2ll;
		a[i] = lim;
	}
	priority_queue <ll> q;
	for(int i = 1; i <= n; ++i) q.push(a[i]);
	for(ll i = num + 1; i <= k; ++i)
	{
		ll now = q.top();q.pop();
		if(now <= 0) break;
		ans += now;
		q.push(now - 1);
	}
	cout << ans << endl;
}

int main()
{
	ios::sync_with_stdio(0);
	work();
	return ~~(0^_^0);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值