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 }
时间: 2024-10-18 09:28:26

UVAlive7501 Business Cycle 2015ECfinal B(二分模板)的相关文章

Aizu ITP2_6_A(二分模板)

For a given sequence $A = \{a_0, a_1, ..., a_{n-1}\}$ which is sorted by ascending order, find a specific value $k$ given as a query. Input The input is given in the following format. $n$ $a_0 \; a_1 \; ,..., \; a_{n-1}$ $q$ $k_1$ $k_2$ : $k_q$ The n

Honk&#39;s pool(二分模板题)

题意:有n个水池,每个水池有a[i]单位水,有k次操作,每次操作将水量最多的水池减少一单位水,水量最少的水池增加一单位水,问最后水量最大的水池和水量最少的水池相差的水量. 思路:二分最后的最大水量和最小水量,特别的,模拟一下可以发现如果总水量sum%n==0,则最大值的下界和最小值的上界均为sum/n,若sum%n!=0,则最大值的下界为sum/n+1,最小值上界为sum/n.二分时注意选取区间是左闭右开还是左开右闭. #include <iostream> #include <algo

二分模板// The Frog&#39;s Games +Aggressive cows

  二分的情况不同所输出的模板也不同列如下面两个题目                                                    The Frog's Games   代码如下               //二分专练                                                #include <stdio.h> //lower_bound大于等于它的第一个数                                     

UVALive 7501 Business Cycle(二分)题解

题意:n个数,有一个起始值,按顺序从第一个开始不断循环取数,如果取完后相加小于0就变为0,最多取p个数,问你得到大于等于值g所需要的最小起始值为多少 思路:这题目爆long long爆的毫无准备,到处都有可能爆值. 显然,我们能想出,初始值越大,那么走相同步数所得到的数字就会越大(或相等),那么我们就可以用二分法每次判断是否能得到g值,大概logG * n * C的复杂度.那么现在问题就是怎么判定初始值s是否能得到g值. 我们可以求循环两次的结果差dis = tot2 - tot1,来判断每次循

二分模板

从卿学姐那里偷来的模板 (整数二分  待更新更加高级的 int left = 0,ri =maxn; while (left <= ri) { int mid = (left + ri)/2; if( check(mid) ) ans=mid,left = mid+1; else ri= mid-1; } cout << ans <<endl;

AcWing 789. 数的范围 二分+模板

https://www.acwing.com/problem/content/791/ #include<bits/stdc++.h> using namespace std; const int N=100010; int n,m; int q[N]; int main() { scanf("%d%d",&n,&m); for(int i=0; i<n; i++) scanf("%d",&q[i]); while(m--)

【模板整合】整体二分模板

模板题目:ZJOI2013 K大数查询原题是带插入区间第K大 注释足够看→_← #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #define MAXN 50010 #define MAXINT 0x7fffffff #define lchild rt<<1,l,mid #define rchild rt

各种类型的二分模板

1.查找最后一个小于或者等于key的下标,若不存在,则返回-1 ==> 同lower_bound(arr+1, arr+1+n, key) int BinSearch(int a[], int n, int key) { int m, l = 0, r = n - 1;//闭区间[0, n - 1] while (l <= r) { m = (l+r)/2; if (a[m] <= key) l = m + 1; else if(a[m] > key) r = m - 1; } i

二分之万无一失的模板~~~

My first blog~~~. 这里给个二分的模板 1 //二分模板 2 l = 0;r += 10;//保证所有元素都有可以被遍历的机会 3 while(l + 1 < r) 4 { 5 int mid = l + r >> 1; 6 if(check(mid)) l = mid; 7 else r = mid; 8 } 原文地址:https://www.cnblogs.com/QuickSilverX/p/10352129.html