题意:
给出每个关卡的得分。每次过关都加上当前的的关卡分数,如果小于0就变为0.
思路:
手动出了无数组样例, debug了一个多小时。。。T-T终于AC了
二分一个值,判断是否能够通过若干关后,满足要求。
二分判断条件:
1.如果跑一次,和跑两次,得分都是一样的,或者更小,那么必定有一个 相对于其他值来说是一个-inf的值,因此就在一圈,一圈~两圈之内跑。
2.如果不够跑两圈,那么也是在跑一圈之内,一圈到两圈之内跑。
3.如果够了两圈而且跑尽可能多的圈数合适,那么也有两种情况:
假如能跑n圈,以及mo个关卡
3.1 如果一个负值的洞出现在最接近结束的位置, 那么我们要判断n-1圈 + 跑1圈的最大值,以求避过那个负值
3.2 没什么好说的,就跑n圈和mo个关卡的最大值
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 50;
ll a[N], n, p, g;
ll cir(ll k){
ll num = k;
for(int i = 0; i < n; i++) {
num += a[i];
if(num < 0) num = 0;
}
return num;
}
ll cirmax(int pos, ll k){
ll num = k, maxx = k;
for(int i = 0; i < pos; i++){
num += a[i];
if(num < 0) num = 0;
maxx = max(num, maxx);
}
return maxx;
}
bool judge(ll k){
ll re1 = cir(k), ans = 0;
ll re2 = cir(re1);
if(re1 >= re2 || p < 2 * n) {
// cout << k << " " << 1 << endl;
if(p > n ) {
ans = max(ans, cirmax(n, k));
if(p < 2 * n)ans = max(ans, cirmax(p - n, re1));
else ans = max(ans, cirmax(n, re1));
}else{
ans=max(ans,cirmax(p,k));
}
}else {
ll times = p / n, mo = p % n;
if((g - re1) / (re2 - re1) < times-1) return 1;
ll sum2 = 0, sum1 = max(0LL, times - 1) * (re2 - re1) + re1;
sum1 = cirmax(mo, sum1);
sum2 = max(0LL, times - 2) * (re2 - re1) + re1;
sum2 = cirmax(n, sum2);
ans = max(ans, max(sum1, sum2));
}
return ans >= g;
}
int main(){
int T;
scanf("%d", &T);
for(int kase = 1; kase <= T; kase++){
scanf("%lld%lld%lld", &n, &g, &p);
for(int i = 0; i < n; i++) scanf("%lld", &a[i]);
ll l = 0, r = g, ans = g;
while(l <= r) {
ll mid = (l + r) / 2;
if(judge(mid)) {
ans = mid;
r = mid - 1;
}else l = mid + 1;
}
printf("Case #%d: %lld\n", kase, ans);
}
return 0;
}