UVAlive7501 Business Cycle 2015ECfinal B(二分模板)

题意:给你一个环,环有n个点,编号0~n-1,每个点有一定的权值,从点0出发沿编号走,到达某一个节点则把目前总权值加上这个节点的权值,如果结果小于0则变成0。现在给你最多可以走的步数P和最大需要到达的权值大小G,问你需要的最小的初始权值为多少,能在P步内能够产生的最大权值大于等于G


题解:很容易想到初始权值越大,经过同样步数能够得到的权值就越大,当然是非严格递增的。那么直接想办法二分寻找初始权值就可以。但是如果步数太大了就没法模拟了,所以要消除步数的影响。步数的影响主要来源于在走环的过程中可能由负数变为0,不然直接预处理就可以了。所以先找出走环过程能够始终不小于0所需要的最小权值sum,当初始权值小于sum时会在过程中变为0,那么用这个初始权值走一圈以上就等效于用0走一圈以上,当然走一圈以内是不能等效的,一圈以内所能得到的最大权值可能大于初始为0开始走。当初始权值大于等于sum时走一圈如果总权值减小那么可以到达的最大权值必定在一圈以内,如果增大则需要分情况讨论了,具体见代码,比较坑就是比较是否是否能到达所需要的G时可能爆long long ,,,,

  1 #include <iostream>
  2 #include <algorithm>
  3 #include <cstdio>
  4 #include <cmath>
  5 using namespace std;
  6 typedef long long ll;
  7 const ll maxn = 1e5 + 10;
  8 ll a[maxn];
  9 ll n,g,p;
 10 ll getm(ll u,ll num) { //初始为u走num步过程中可得的最大值
 11     ll max1 = u;
 12     for(ll i = 0; i < num; i++) {
 13         u += a[i];
 14         if(u < 0) u = 0;
 15         max1 = max(max1,u);
 16     }
 17     return max1;
 18 }
 19 int main() {
 20    // freopen("in.txt","r",stdin);
 21     //freopen("out.txt","w",stdout);
 22     ll T;
 23     cin>>T;
 24     ll cas = 0;
 25     //ll l = (ll)3e18+7;
 26     //cout<<l<<endl;
 27     while(T--) {
 28         cas++;
 29         scanf("%lld%lld%lld",&n,&g,&p);
 30         for(ll i = 0; i < n; i++) scanf("%lld",&a[i]);
 31         ll sum = 0,sum0 = 0;//sum 为始终不小于0的界限,sum0初始为走一圈所得的值
 32         for(ll i = 0; i < n; i++) {
 33             sum0 += a[i];
 34             if(sum0 < 0) {
 35                 sum -= sum0;
 36                 sum0 = 0;
 37             }
 38         }
 39         //cout<<sum<<" "<<sum0<<endl;
 40         ll sums = sum;//sums为sum走一圈所得的值
 41         for(ll i = 0; i < n; i++) sums += a[i];
 42         sums -= sum;
 43         ll max0;//max0为0走一圈以上所得的最大值
 44         if(p > n) {
 45             if(sum0 < sum) {
 46                 if(p < 2*n)
 47                     max0 = getm(sum0,p - n);
 48                 else
 49                     max0 = getm(sum0 , n);
 50             }
 51             else {
 52                 if(p < 2 * n) max0 = getm(sum0,p - n);
 53                 else {
 54                     if(sums > 0) {
 55                        if((g-sum0)/sums < p/n-1)//每一圈都能增大sums,当走最多圈是否能到达所需要的值
 56                         max0 = g+1;
 57                       else{
 58                         max0 = sum0 + sums*(p/n-1);
 59                         max0 = getm(max0,p % n);
 60                         if(p/n > 1) {//当少走一圈时是否可以到达更大的值
 61                             ll max1 = (p/n - 2)*sums + sum0;
 62                             max1 = getm(max1,n);
 63                             max0 = max(max0,max1);
 64                         }
 65                     }
 66                     }
 67                     else {
 68                         max0 = getm(sum0,n);
 69                     }
 70                 }
 71             }
 72         }
 73 
 74         ll l = 0,r = g;
 75         ll xans = -1;
 76         while(l <= r) {
 77             ll mid = l + (r - l) / 2;
 78             ll ans = mid;
 79             if(p <= n){
 80                 ans = getm(mid,p);
 81             }
 82             else {
 83                 //cout<<ans<<endl;
 84                 if(mid < sum) {
 85                     ans = getm(mid,n);
 86                     ans = max(ans,max0);
 87              //   cout<<ans<<endl;
 88                 }
 89                 else {
 90                     if(sums > 0) {
 91                         //cout<<sums*(p/n)<<endl;
 92                         if((g-mid)/sums < p/n-1) ans = g+1;//同上
 93                         else{
 94                         ans += sums*(p/n);
 95                         ans = getm(ans,p % n);
 96                       // cout<<ans<<endl;
 97                         if(p/n >= 1) {
 98                             ll ans1 = 0;
 99                             ans1 = sums*(p/n-1) + mid;
100                             ans1 = getm(ans1,n);
101                             ans = max(ans,ans1);
102                         }
103                         }
104                     }
105                     else ans = getm(mid,n);
106                    // cout<<ans<<endl;
107                 }
108             }
109           //  cout<<l<<" "<<r<<" "<<mid<<" "<<ans<<endl;
110             if(ans >= g) r = mid - 1, xans = mid;
111             else l = mid + 1;
112         }
113         printf("Case #%lld: %lld
",cas,xans);
114     }
115 
116     return 0;
117 }
原文地址:https://www.cnblogs.com/shimu/p/5948176.html