Codeforces 651D Image Preview【二分+枚举】

题意:

若干张照片,从头开始可以向左右两边读,已经读过的不需要再读,有的照片需要翻转,给定读、滑动和翻转消耗的时间,求在给定时间内最多能读多少页?

分析:

首先明确,只横跨一次,即先一直读一边然后再一直读另一边,这样消耗的滑动时间最少。是否能在给定时间内读完页数很好判断,所以用二分+枚举,先枚举左边的所有可能情况,再二分右边求出最大页数, 再枚举右边,求出左边。取两边的最大值即可。

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn = 500005, INF = 0x3f3f3f3f;
int ta, tb, n, T;
ll t[maxn], t1[maxn];
int main (void)
{
    cin>>n>>ta>>tb>>T;
    string s;
    char a; cin>>a;
    if(a=='w') T-=tb;
    T--;
    if(T<0){
        cout<<0<<endl;
        return 0;
    }
    cin>>s;
    for(int i = 0; i < n - 1; i++){
        t[i] = t[i -1] + 1 + ta;
        if(s[i] == 'w') t[i] += tb;
    }
    reverse(s.begin(), s.end());
    for(int i = 0; i < n - 1; i++){
        t1[i] = t1[i -1] + 1 +ta;
        if(s[i] == 'w') t1[i] += tb;
    }
    int res = 0;
    for(int i = 0; i < n; i++){
        if(t1[i - 1] > T) break;
        int l = 0, r = n - i ;
        while(l < r - 1){
           int mid = (l + r)/2;
           if(mid > 0 && t1[i - 1]+ t[mid - 1] + i * ta <= T) l = mid;
           else r = mid;
        }
      res = max(res, l + i);
    }

    for(int i = 0; i < n; i++){
        if(t[i - 1] > T) break;
        int l = 0, r = n - i;
        while(l < r - 1){
            int mid = (l + r)/2;
            if(mid > 0 && t[i - 1]+ t1[mid - 1] + i * ta <= T) l = mid;
            else r = mid;
        }
      res = max(res, l + i);
    }

    cout<<res + 1<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/Tuesdayzz/p/5758750.html