题目描述
你是银狼,在半年多前的一次对决中,你在模拟宇宙和黑塔的对决失败了,76 个游戏账号全被注销。
至今你都有点不甘心,因此这次你作为骇客在骇入黑塔的模拟宇宙 lite 版,模拟宇宙 lite 版由一排房间组成,编号 i 范围 [0,n],你一开始在 0 号房间,你只能从 i 号房间走到 i+1 号房间。
你有生存值属性,初始生存值为 M,生存值不能小于 0。
房间分为挑战房间、奖励房间和事件房间。在挑战房间,你可以选择挑战里面的怪物,挑战怪物会消耗生存值 ai;在奖励房间,你可以获得 ai 点生存值。领取奖励和挑战怪物视为通关这个房间。同时,存在事件房间,这些房间被黑塔设置了安全限制,因此你无法跳过这个房间,必须通关这个房间,必须消耗 ai 生存值。
由于你是技术高超的骇客,你可以选择不挑战或不接受奖励而直接走到下一个房间(视为没有通关这个房间)。但是黑塔的安全系统也不是摆设,而且你的目的只是为了捣乱,你不想被发现,所以整个骇入过程你最多只能损失 S 点生存值。走出 n 号房间即完成骇入;虽然中途退出很逊,但是你不想再失去 76 个游戏账号,所以即使你没法走到 n 号房间你还是会直接退出,表示还是黑塔更胜一筹。
问最多通关几个房间?
输入描述:
第一行输入 n,M,S (1≤n≤10^6,1≤M,S≤10^12)
第二行有 n个数 a1,a2...an(0≤ai≤106)表示每个房间需要消耗或奖励的生存值。
第三行有 n 个数 x1,x2...xn 表示第 i 房间的种类(1≤xi≤3)。xi=1表示这个房间为挑战房间;xi=2 表示这个房间为奖励房间;xi=3 表示这个房间为事件房间。
输出描述:
一个整数,表示最多通关房间数量。
示例1
输入
6 6 10
1 1 4 5 1 4
1 2 1 3 1 2
输出
5
说明
对于样例,
房间 1 选择挑战,生存值 M=5,共消耗生存值 sum=1;
房间 2 选择奖励,生存值 M=6,共消耗生存值 sum=1;
房间 3 不挑战,生存值 M=6,共消耗生存值 sum=1;
房间 4 必须消耗,生存值 M=1,共消耗生存值 sum=6;
房间 5 选择挑战,生存值 M=0,共消耗生存值 sum=7;
房间 6 选择奖励,生存值 M=4,共消耗生存值 sum=7。
#include<iostream>
#include<cstring>
#include<queue>
#define int long long
using namespace std;
const int N=1e6+10;
int a[N],x[N];
int n,m,s;
void solve()
{
scanf("%lld%lld%lld",&n,&m,&s);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1;i<=n;i++) scanf("%lld",&x[i]);
priority_queue<int,vector<int>,less<int>>q;
int ans=0;
int sum=0;
int mx=m,sx=0;
for(int i=1;i<=n;i++)
{
//当x=1时 可以挑战
//用贪心的思想来做 若当前剩余的生存值和消耗的生存值没有大于s 直接要推进大根堆
//若不行 则看与大根堆中最大的对堆顶相比哪个大 若堆顶大的话 就跳过堆顶的房间 走当前这个
//则弹出堆顶 将当前值推入推中 更新相应的房间数 生存值 消耗二等生存值
//若比堆顶元素还大 就直接不要这个房间 (贪心 )(房间这么大要它干嘛)
if(x[i]==1)
{
if(mx>=a[i]&&sx+a[i]<=s)
{
mx-=a[i];
sx+=a[i];
q.push(a[i]);
sum++;
}
else
{
if(q.size()&&a[i]<q.top())
{
int num=q.top();
q.pop();
mx+=num;
sx-=num;
mx-=a[i];
sx+=a[i];
q.push(a[i]);
}
}
}
//x==2时 此时房间时奖励 奖励全都要 直接更新房间数和生存值
else if(x[i]==2)
{
sum++;
mx+=a[i];
}
//x==3时 必须挑战 若能挑战过去则能继续往右走 更新 若不能直接终止
//首相判断当前的生存值和消耗的生存值是否能满足走这个房间的条件 若能直接更新即可
//若不能则考虑 可以让几个x==1的房间跳过 去看能否满足条件
//此时遍历大根堆 不断减少x==1的房间数 看是否行 可行就退出循环 然后更新相应的条件
//若堆都已经空了且当前的条件仍不能满足 则直接跳出循环
else
{
if(mx>=a[i]&&sx+a[i]<=s)
{
mx-=a[i];
sx+=a[i];
sum++;
}
else
{
//不要这样写 这样写不对 当出现大根堆为空也不无法满足条件时
//就应该直接退出 不往下遍历 如果这样写 循环不会终止
/* while(q.size())
{
int num=q.top();
mx+=num;
sx-=num;
sum--;
if(mx>=a[i]&&sx+a[i]<=s)
{
sum++;
mx-=num;
sx+=num;
break;
}
}
}*/
while(q.size()&&(mx<a[i]||sx+a[i]>s))
{
int t=q.top();
q.pop();
mx+=t;
sx-=t;
sum--;
}
if(mx<a[i]||sx+a[i]>s)
{
break;
}
mx-=a[i];
sx+=a[i];
sum++;
}
}
ans=max(ans,sum);
}
cout<<ans<<endl;
}
signed main()
{
solve();
return 0;
}