AcWing 1913. 公平摄影

·  阅读 614

目录:算法日记

题目来源:1913. 公平摄影 - AcWing题库

题目描述

农夫约翰的 NN 头奶牛站在一维长围栏的不同位置。

第 ii 头牛位于位置 xix_i,其所属品种为 bib_i(根西岛牛或荷斯坦牛)。

所有奶牛的位置各不相同。

约翰想给一段连续区间内的奶牛拍摄一张照片,用来在乡村集市上展览。

但是我们希望他所有品种的奶牛都能在照片中得到公平的展示。

因此,他希望确保无论照片中出现哪些品种的奶牛,每种品种的奶牛在照片中的数量都必须相等。

例如,一张照片中只包含荷斯坦牛是可以的,包含荷斯坦牛和根西岛牛各 2727 头也没问题,但是包含 1010 头荷斯坦牛和 99 头根西岛牛则不可以。

请确定,约翰可以拍下的满足以上条件的照片的最大尺寸。

照片的尺寸是指照片中奶牛最大和最小位置之间的差。

约翰最终可能只拍下一头奶牛,这种情况下,照片尺寸为 00

输入格式

第一行包含整数 NN

接下来 NN 行,每行包含一个整数 xix_i 和一个字符 bib_iHH 表示荷斯坦牛,GG 表示根西岛牛)。

输出格式

输出照片的最大尺寸。

数据范围

  • 1N1051≤N≤10^5
  • 0xi1090≤x_i≤10^9

输入样例

6
4 G
10 H
7 G
16 G
1 G
3 H
复制代码

输出样例

7
复制代码

算法思路

满足题目要求的最大图片尺寸有如下三种情况:

  1. 仅包含 HH 荷斯坦牛;
  2. 仅包含 GG 根西岛牛;
  3. 包含数量相等的 HH 荷斯坦牛与 GG 根西岛牛;

情况(3)较复杂,先考虑如何处理。包含数量相等的两种牛,为方便处理,可以分别用±1±1来表示牛的种类,当照片尺寸覆盖的牛种类和 sum==0sum == 0 时,说明数量相等。且由于输入顺序是乱序,因此,对输入数据需按坐标进行排序。

通过上述操作,我们已经可以通过暴力遍历的方法得到最大的照片尺寸,但时间复杂度为O(n2)O(n^2),考虑优化。

由于尺寸的定义是最大和最小位置之间的差,我们需要记录一个最小位置。定义当前位置的sumsum与最小位置的sumsum相等时(即当前位置到最小位置之间的两种牛数量相等),该照片便是合法照片,且有尺寸极大值。则最小位置为sumsum第一次出现的位置。

这里存在一个细节问题。对牛种类的求和处理实际使用的是前缀和,前缀和计算公式为:sumrsuml1sum_r - sum_{l-1},我们需要求的照片尺寸应为rlr-l。因此在存储最小位置(左端点)时,应取[0,l1][0, l-1]范围内的前缀和,但在判断时,前缀和范围为[0,r][0, r]

对于情况(1)(2)也可能存在最大尺寸照片,保存更新相同品种牛的最小位置,暴力判断即可。

AC代码

#include<iostream>
#include<map>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
pair<int, int> nums[N];
map<int, int> dic;
int n;
int main() {
    cin>>n;
    for(int i = 1; i <= n; ++i) {
        int x;
        char b;
        cin>>x>>b;
        if(b == 'G') nums[i] = {x, 1};
        else nums[i] = {x, -1};
    }
    sort(nums + 1, nums + 1 + n);
    
    int last = 0; // 相同品种
    int sum = 0; // 不相同品种
    int res = 0;
    for(int i = 1; i <= n; ++i) {
        //添加最小位置,不包含nums[i]
        if(!dic.count(sum)) dic[sum] = nums[i].first; 
        //比较前缀和,包含nums[i]
        sum += nums[i].second;
        if(dic.count(sum)) res = max(res, nums[i].first - dic[sum]); 
        
        //相同品种
        if(i == 1 || nums[i].second != nums[i - 1].second) last = nums[i].first;
        res = max(res, nums[i].first - last);
    }
    cout<<res<<endl;
    return 0;
}
复制代码
分类:
代码人生
标签:
分类:
代码人生
标签:
收藏成功!
已添加到「」, 点击更改