题目大意:
一道差分和二分的题目,看了别人的博客,发现很少有人用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();
}
}