Kralj

link

一个有趣且古老的贪心题,有些思维难度。

首先把精灵选择矮人的过程替换为矮人选择精灵的过程,每个矮人有许多精灵可以选择,他只能选择其中一个,剩下的精灵可以推给下一个矮人,这样一来就变成了什么样的策略使得矮人输的次数更大。对于一个矮人,假如存在比它强的精灵那么一定会选,因为多赢一次总是好的;那假如没有呢,就直接选择最弱的精灵,为后面的选择留出尽量多的有生力量显然是最优的,于是就变成了一个二分查找的问题,用set维护即可(vector每次要排序不是非常划算)。然后问题成了第一个选择精灵的矮人是谁(也就是从哪个矮人枚举起走)。假如一个位置 i ,有精灵会从 i 这里被送走,当且仅当以它为右端点的一个区间消耗不完所有的精灵,即 ji,sumisumj1ij+1,移项得到: ji,sumj1(j1)sumii 。所以呢,只要 sumii 最小的 i ,就不存在有比它更小的值,也就不存在可能会精灵溢出的区间,也就不会有精灵经过了。

#include<bits/stdc++.h>
//#define feyn
#define p(x) x%m+1
const int N=500010;
using namespace std;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
    wh*=f;return;
}

vector<int>s[N];
set<int>now;
int m,ans,in,a[N],b[N],sum[N];

signed main(){
	
	#ifdef feyn
	freopen("in.txt","r",stdin);
	#endif
	
	read(m);
	for(int i=1;i<=m;i++)read(b[i]);
	for(int i=1;i<=m;i++)read(a[i]);
	for(int i=1;i<=m;i++){
		read(in);s[b[i]].push_back(in);
	}
	int min_=1e9,an_pl,now_sum=0;
	for(int i=1;i<=m;i++){
		now_sum+=s[i].size();
		if(now_sum-i<min_)min_=now_sum-i,an_pl=i;
	}
	for(int i=p(an_pl);;i=p(i)){
		for(vector<int>::iterator it=s[i].begin();it!=s[i].end();it++)now.insert(*it);
		set<int>::iterator it=now.lower_bound(a[i]);
		if(it==now.end())now.erase(now.begin());
		else now.erase(it),ans++;
		if(i==an_pl)break;
	}
	printf("%d\n",ans);
	
	return 0;
}
posted @   Feyn618  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示