E. Turtle vs. Rabbit Race: Optimal Trainings

题目大意:

 一道差分和二分的题目,看了别人的博客,发现很少有人用stl做,那么我就来用stl解决一下这个问题。首先题目大意就是数组里的元素代表部分的个数,而你的分数,不仅仅简单取决于完成部分的多少,随着完成的部分越多,所能获得的分数会越少甚至为负数。题目结合案例的分析不难发现肯定需要前缀和和差分来计算最优方案,然后看到q的范围,应该也会用到二分来控制时间复杂度。那么我一开始考虑的是如果是不是只要活动的分为正,就是最优解?其实不然,因为即使后边活动的得分会是负数,也有可能比活动得分为正数总共得到的分数高,可以结合第3个案例的第二次查询,不难发现,完成第15个活动要比只完成5个活动得分要高。

那么我们就要考虑怎么样才可以得分最高?其实只要活动的个数越靠近u,能得到的分数自然就会高,也自然就是最优解,因此只需要查找u的左边,和u的右边,对比一下左右到u的绝对值谁的更小,然后输出下表就可以了。

查找左边需要lowerbound,注意细节(按照题目所说,我们查找到第一个小于等于u的即可,因为的分是u,u-1......以此类推)右边只需要upperbound,同时要注意,千万得把前缀和数组最后一位的下一位赋值为无限大,否则比较绝对值会出现问题。

ac代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<limits.h>
#include<vector>
#include<cmath>
#include<stack>
#include<queue>
#include<string>
#include<unordered_map>
#include<unordered_set>
#include <iomanip>
#include<set>
#include<map>
using namespace std;
#define N 100006
#define ll long long 
int test;
inline void R(ll& x) {
    ll c;
    x = 0;
    do {
        c = getchar();
    } while (c < '0' || c > '9');
    do {
        x = x * 10 + c - '0';
        c = getchar();
    } while (c >= '0' && c <= '9');
}
ll min(ll a, ll b)
{
    return a < b ? a : b;
}
int n;
ll a[N];
ll pre[N];
int q, l;
ll u;
void solve()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        pre[i] = pre[i - 1] + a[i];
    }
    pre[n + 1] = INT64_MAX;
    cin >> q;
    while (q--)
    {
        cin >> l >> u;
        int pos =lower_bound(pre +1+l, pre + 1 + n, u+pre[l-1]) - pre;
        if (pre[pos] - pre[l - 1] !=u)pos--;
        int p = upper_bound(pre + 1 + l, pre + 1 + n, u + pre[l - 1]) - pre;
        int ans = 0;
        if (abs(pre[p] - pre[l - 1] - u) >abs(pre[pos] - pre[l - 1]-u))ans = pos;
        else ans = p;
        cout << ans << ' ';
    }
    cout << endl;
}
 
int main()
{
    int test;
    ios::sync_with_stdio(0);
    cin >> test;
    while (test--)
    {
        solve();
    }
}

  • 45
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值