G. Old Floppy Drive
题意:
给定一个循环数组和
x
x
x,从第一位开始累加,直到
s
u
m
>
=
x
sum >= x
sum>=x 为止,问需要累加多少次或者永远不能达到
思路:
先求一个数组和
s
u
m
sum
sum 和最大前缀和
p
r
e
_
m
a
x
pre\_max
pre_max
如果满足
p
r
e
_
m
a
x
<
x
&
&
s
u
m
<
=
0
pre\_max<x \ \&\& \ sum <= 0
pre_max<x && sum<=0,则无解
然后
p
r
e
_
m
a
x
pre\_max
pre_max 和
s
u
m
sum
sum 满足一个关系,
p
r
e
_
m
a
x
>
=
s
u
m
pre\_max >= sum
pre_max>=sum
为了使答案尽量小,显然我们应该尽量让最后一次循环截止到
p
r
e
_
m
a
x
pre\_max
pre_max 的及其之前的位置
然后先执行
c
n
t
=
(
x
−
p
r
e
_
m
a
x
+
s
u
m
−
1
)
/
s
u
m
cnt = (x-pre\_max+sum-1)/sum
cnt=(x−pre_max+sum−1)/sum 次,最后剩下
x
−
c
n
t
∗
s
u
m
x-cnt*sum
x−cnt∗sum
剩下的部分我们可以考虑二分查找
显然直接求得的前缀和是不单调的,即使我们加上
i
d
id
id 后对前缀和进行排序,也无法得到最优解
因为们要查找应该是满足
p
r
e
_
m
a
x
>
=
x
pre\_max>=x
pre_max>=x 的前缀和中最
i
d
id
id 最小的一个
参考这个大佬的思路
可以发现如果
p
r
e
[
i
]
>
=
p
r
e
[
i
+
1
]
pre[i]>=pre[i+1]
pre[i]>=pre[i+1],那么
p
r
e
[
i
+
1
]
pre[i+1]
pre[i+1] 显然永远不会作为答案的,这是一个无效点,因为有更优的
p
r
e
[
i
]
pre[i]
pre[i]
因此可以考虑维护一个单调递增的
p
r
e
pre
pre 数组,这时就可以二分得到最优解
code:
#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define eps 1e-6
using namespace std;
const int maxn = 2e5 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
void work()
{
scanf("%lld %lld", &n, &m);
ll sum = 0;
vector <ll> pre, id;
for(int i = 1, x; i <= n; ++i){
scanf("%d", &x);
sum += x;
if(pre.empty() || pre.back() < sum)
pre.push_back(sum), id.push_back(i);
}
while(m--){
int x;scanf("%d", &x);
if(pre.back() < x && sum <= 0) printf("-1 ");
else
{
ll cnt = 0;
if(pre.back() < x) cnt = (x - pre.back() + sum - 1) / sum;
x -= cnt * sum;
int pos = lower_bound(pre.begin(), pre.end(), x) - pre.begin();
printf("%lld ", cnt * n + id[pos] - 1);
}
}
printf("\n");
}
int main()
{
// ios::sync_with_stdio(0);
int TT;cin>>TT;while(TT--)
work();
return 0;
}
本文探讨如何在给定循环数组中,通过最少的累加操作使其和至少达到目标值x。关键步骤包括计算最大前缀和与剩余值的关系,利用单调递增数组和二分查找来找到最优解。
359

被折叠的 条评论
为什么被折叠?



