题意:给你一个环,环有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 }