蓝桥杯算法训练 礼物

这篇博客主要讨论了一个关于旅行纪念品的问题。JiaoShou在爱琳大陆旅行结束后,打算带些石子作为礼物,但石子带有特殊魔法,需要每次取连续的2*K个且重量不超过S。JiaoShou需要找到最多能取走多少个石子。博主首先尝试了直接遍历的解法,但遇到问题,然后改用二分搜索来优化算法,以提高效率。
摘要由CSDN通过智能技术生成

这里写自定义目录标题

问题描述
JiaoShou在爱琳大陆的旅行完毕,即将回家,为了纪念这次旅行,他决定带回一些礼物给好朋友。
  在走出了怪物森林以后,JiaoShou看到了排成一排的N个石子。
  这些石子很漂亮,JiaoShou决定以此为礼物。
  但是这N个石子被施加了一种特殊的魔法。
  如果要取走石子,必须按照以下的规则去取。
  每次必须取连续的2*K个石子,并且满足前K个石子的重量和小于等于S,后K个石子的重量和小于等于S。
  由于时间紧迫,Jiaoshou只能取一次。
  现在JiaoShou找到了聪明的你,问他最多可以带走多少个石子。

输入格式
第一行两个整数N、S。
  第二行N个整数,用空格隔开,表示每个石子的重量。

输出格式
第一行输出一个数表示JiaoShou最多能取走多少个石子。

样列输入
8 3
1 1 1 1 1 1 1 1

样列输出
6

思路
最开始思路就是直接遍历,但仅成功第二个数据,第一个数据不知道到为什么没有成功,后几个超时

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

int get(vector<int> nums)
{
    return 0;
}
int main()
{
    ios::sync_with_stdio(false);
    long long  n, m;
    cin >> n >> m;
    long long x1 = 0;
    long long x2 = 0;
    long long s=0;
    int flag = 0;
    vector<int> a(n+1);
    for(long long i=0;i<n;i++)
    {
        cin >> a[i];
    }
    for (long long i = n/2; i >=1; i --)
    {
        for (long long j = 0; j <= n / 2 - i; j++)
        {
            x1 = accumulate(a.begin() + j, a.begin() + i + j, 0LL);
            if (x1 > m)
            {
                continue;
            }
            x2 = accumulate(a.begin() + i + j, a.begin() + i + i + j, 0LL);
            if (x2 > m)
            {
                continue;
            }
            else
            {
                cout << i * 2;
                flag = 1;
                break;
            }
        }
        if (flag == 1)
        {
            break;
        }
    }
    return 0;
}

超时改用二分方法

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int M = 1e6+5;
int N;long long S;
long long val[M], a[M]; //前缀和,石子每个的质量
bool check(int mid)
{
    for (int i = mid; i <= N-mid; i++)
    {
        if (val[i] - val[i - mid] <= S && val[i + mid] - val[i] <= S)
        {
            return true; //存在符合情况的
        }
    }
    return false;
}
int main()
{
    cin >> N >> S;
    for (int i = 1; i <= N; i++)
    {
        cin >> a[i];
        val[i] = val[i - 1] + a[i]; //求前缀和
    }
    //找符合要求的最大值采用二分法
    int l = 1, r = N;
    while (l < r)
    {
        int mid = l + r + 1 >> 1; //(l+r)/2,这里mid代表了单个区域所取石子的股数
        if (check(mid))//成功说明当前区域可取
        {
            l = mid;//增大l-》增大下一次的mid
        }
        else
            r = mid - 1;//r减小-》减小下一次的mid
    }
    cout << 2 * l << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值