首页 > 代码库 > UVAlive7501 Business Cycle 2015ECfinal B(二分模板)

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\n",cas,xans);114     }115 116     return 0;117 }

 

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