最大通过数 二分 前缀和

问题描述

洛洛和晶晶计划一起挑战峡谷深渊,这个深渊有两个入口,分别为左边和右边。左边的入口有 n 个关卡,第 i 个关卡需要消耗 ai​ 块能源紫水晶。右边的入口有 m 个关卡,第 ii 个关卡需要消耗 bi​ 块能源紫水晶。为了挑战下一个关卡,两个入口的关卡必须按顺序通过。

洛洛决定选择左边的入口,而晶晶决定选择右边的入口。两人总共只携带了 k 块能源紫水晶。他们不确定如何分配能源才能使得通过的关卡数之和最大。你需要帮助他们求出通过的关卡数之和的最大值。请注意,你无需给出具体的能源分配方案,只需要计算可以达到的最大关卡数之和。

输入格式

第一行输入三个整数 n​,mm​,k​​ 。

第二行输入 n 个整数 ai​ 。

第三行输入 m 个整数 bi​ 。

数据范围保证:1≤n,m≤2×105,1≤ai,bi,k≤109.

输出格式

输出一个整数,表示两人通过的关卡数之和最大值。

样例输入

2 2 10
1 2
3 5

样例输出

3

说明

样例中洛洛通过 2 关,晶晶通过 1 关,总共可通过 3 关。

初期想法:(过了1/4)

#include <bits/stdc++.h>
using namespace std;

int n, m, k;

int main() {
    cin >> n >> m >> k;
    int a[n];
    int b[n];
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    for (int i = 1; i <= m; i++) {
        cin >> b[i];
    }

    int s = 0;
    int w;
    int i = 1, j = 1;
    while (k>0) {   //当还有能量的时候执行
        s++;//闯关数增加
        if(i>n &&j<=m)//如果a的关卡闯完了,但b没有
        {
            w=b[j];
        }
        else if(i<=n && j>m)//b没有,a完了
        {
            w=a[j];
        }
        else w = min(a[i], b[j]);

        if (w == a[i] && i <= n) {
            i++;
        } else if (w == b[j] && j <= m) {
            j++;
        }
        k -= w;
        if (k <= 0 ||(i==n+1 && j==m+1)) {
            break;
        }
    }
    if (k < 0) {//多了一次
        s--;
    }
    cout << s << endl;//当k=0时刚好
    return 0;
}

为什么错呢?因为我只比较两个数据没有比较全局:

假设:

a:2 5 1 1 1 1

b:3 4 2 2 2 2            它会一直比较5和2的大小忽略了5+1+1+1+1<4+2+2+2+2.没有考虑周全.

中期:只有前缀和的做法 (过了)

#include<bits/stdc++.h>
using namespace std;
long long int a[200005];
long long int b[200005];
int n,m,k,ans,sum;
int main()
{
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        a[i]+=a[i-1];//前缀和
    }
    for(int i=1;i<=m;i++)
    {
        cin>>b[i];
        b[i]+=b[i-1];
    }
    for(int i=n;i>=0;i--)
    {
        while(a[i]+b[sum]<=k and sum<=m)
        {
            ans=max(ans,sum+i);
            sum++;

        }
        if(sum>m)
        {
            break;
        }
    }
    cout<<ans;
    return 0;
}

最后加上二分的想法 (过了)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
ll a[N],b[N];
ll n,m,k;
ll check(ll mid){//mid为通过关卡数 
    ll ans=k+1;
    for(int i=0;i<=mid;i++){
        if(i>n||mid-i>m)continue;  //不能让a,b越界
        ans=min(ans,a[i]+b[mid-i]);
    }
    return ans;
}

int main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        a[i]+=a[i-1];
    }
    for(int i=1;i<=m;i++){
        cin>>b[i];
        b[i]+=b[i-1];
    }
    ll l=0,r=n+m+1;
    while(l<r){
        ll mid=(l+r)>>1;  
        if(check(mid)>k) r=mid;
            //这里的mid代表通关数通关mid次需要多少快能源紫水晶
        else l=mid;
    }

    cout<<l;

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值