CF650B 照片浏览

1 CF650B 照片浏览

2 题目描述

时间限制 \(1s\) | 空间限制 \(256M\)

\(Vasya\) 的手机里面有 \(n\) 张照片,编号为 \(1\) 的照片正在手机上显示。可以通过手指左右滑动来切换相邻的照片。如果你从第一张照片往左边滑动,你就到了第 \(n\) 张照片。类似的,如果你从第 \(n\) 张照片往右边滑动你就回到了第 \(1\) 张照片。滑动一张照片需要 \(a\) 秒钟。每张照片都有两种方向,横向或者纵向。我们可以直接观看纵向的照片。如果我们要观看横向的照片,我就需要花费 \(b\) 秒钟旋转成纵向。\(Vasya\)\(T\) 秒钟的时间来查看照片,他想尽可能的多看照片。如果 \(Vasya\) 第一次打开照片,他会花 \(1\) 秒钟来查看照片的细节。如果照片的方向不对,在看照片之前他要先花费 \(b\) 秒钟来旋转照片。对于他曾经看过的照片,他会直接忽略,不花费任何时间在上面。不允许忽略没看过的照片。请求出 \(Vasya\)\(T\) 秒内能看到最大的照片数量。

数据范围:\(1 ≤ n ≤ 5·105, 1 ≤ a, b ≤ 1000, 1 ≤ T ≤ 109\)

3 题解

我们发现,由于我们必须看完当前照片再往后翻,我们看到第 \(i\) 张照片所需要的时间其实是确定的。这里我们分三部分计算:往左翻、往右翻、以及先看完一侧后翻到另一侧的时间。如果某张照片在一开始是横着的,那么我们看这张照片的时间就是 \(b + 1\),否则我们看这张照片的时间就是 \(1\)。这里我们设 \(t_i\) 为看第 \(i\) 张照片所用的时间,用 \(sum_1\) 存储向右翻时的时间,用 \(sum_2\) 存储向左翻时的时间。那么就有 \(sum_{1, i} = sum_{1, i-1} + t_i + a + 1\)\(sum_{2, i} = sum_{1, i-1} + t_{n - i + 1} + a + 1\)。这里的 \(sum_{1, i}\) 表示从第一张向右翻 \(i\) 张所需要的时间,\(sum_{1, i}\) 表示从第一张向右翻 \(i\) 张所需要的时间,\(sum_{2, i}\) 表示从第一张向左翻 \(i\) 张所需要的时间。我们可以考虑枚举向左翻动的张数 \(i\),然后二分找到耗费时间最大的我们可以向右翻动看到的照片数 \(j\)。注意这里我们默认是先向左翻,所以总共花费的时间就是 \(sum_{1,i} + i * a + sum_{2, j}\)。然后我们反着枚举向右翻动的张数 \(j\),然后二分找到耗费时间最大的我们可以看到向左翻动看到的照片数 \(i\)。由于默认先向右翻,所以总共花费的时间是 \(sum_{2,j} + j * a + sum_{1, i}\)。将这两种分配方案能看到的照片数取一个 \(max\),再与 \(n\) 取一个 \(min\) 输出。这里与 \(n\)\(min\) 是因为我们枚举的向左和向右的照片可能会重叠,导致答案偏大。

注意在开头减去看第 \(1\) 张照片的时间。

4 代码(空格警告):

#include <iostream>
#include <string>
using namespace std;
const int N = 5e5+10;
int n, a, b, T, l, r, mid, ans, fans;
int sum1[N], sum2[N];
char s[N];
int main()
{
    cin >> n >> a >> b >> T >> (s+1);
    if (s[1] == 'w') T -= b;
    T -= 1;
    if (T < 0)
    {
        cout << 0;
        return 0;
    }
    for (int i = 1; i < n; i++) sum1[i] = sum1[i-1] + (s[i+1] == 'w') * b + a + 1;
    for (int i = 1; i < n; i++) sum2[i] = sum2[i-1] + (s[n-i+1] == 'w') * b + a + 1;
    for (int i = 0; i < n; i++)
    {
        l = 0;
        r = n-1;
        while (l <= r)
        {
            mid = (l+r)/2;
            if (T >= sum1[i] + i * a + sum2[mid]) ans = mid, l = mid+1;
            else r = mid-1;
        }
        if (sum1[i] + i * a + sum2[ans] > T) continue;
        fans = max(fans, ans + i + 1);
    }
    for (int i = 0; i < n; i++)
    {
        l = 0;
        r = n-1;
        while (l <= r)
        {
            mid = (l+r)/2;
            if (T >= sum2[i] + i * a + sum1[mid]) ans = mid, l = mid+1;
            else r = mid-1;
        }
        if (sum2[i] + i * a + sum1[ans] > T) continue;
        fans = max(fans, ans + i + 1);
    }
    cout << min(n, fans);
    return 0;
}

欢迎关注我的公众号:智子笔记

posted @ 2021-02-23 21:42  David24  阅读(45)  评论(0编辑  收藏  举报