「USACO11NOv1」 Cow Lineup S

「USACO11NOv1」 Cow Lineup STj


问题描述

农民约翰雇一个专业摄影师给他的部分牛拍照。由于约翰的牛有好多品种,他喜欢他的照片包含每个品种的至少一头牛。

约翰的牛都站在一条沿线的不同地方, 每一头牛由一个整数位置 X i X_i Xi以及整数品种编号 I D i ID_i IDi表示。

约翰想拍一张照片,这照片由沿线的奶牛的连续范围组成。照片的成本与规模相当,这就意味着,在一系列照片中的最大和最小 X X X坐标的差距决定了照片的成本。(一个提示)

请帮助约翰计算最小的照片成本,这些照片中有每个不同的品种的至少一头牛,没有两头牛愿意站在同一个地点的。

输入格式

1 1 1行:牛的数量 N ( 1 < = N < = 50 , 000 ) N(1<=N<=50,000) N(1<=N<=50,000);

2 2 2行:每行包含 2 2 2个以空格分隔的正整数 X i X_i Xi I D i ID_i IDi;意义如题目描述;

输出格式

输出共一行,包含每个不同品种 I D ID ID的照片的最低成本。


分析

因为所有牛都在一条线上,且都有一个不同的坐标( X i X_i Xi),所以可以用一个一维数组存,因为 X i X_i Xi不知道范围,所以用i来定范围方便一些。题目中说了,一头牛有两个信息: X i X_i Xi坐标和 I D i ID_i IDi品种,所以用一个结构体数组来存储每一头牛的信息

#define LL long long
struct COW{
    LL x,d;//x是坐标,d是品种,避免爆炸开long long
}cow[50005];

因为输入坐标时是乱的,使用双指针需要一个有序的序列,所以要对它排序,题目中要求在原序列中选取一段区间,所以要用 X i X_i Xi排序,用map<LL,LL> v1记录 I D i ID_i IDi的头数

#define LL long long
map<LL,LL> v1,v2;//v11的作用后面讲
bool cmp(COW a,COW b){
    return a.x<b.x;
}
scanf("%d",&n);
for (LL i=1;i<=n;++i){
    scanf("%lld %lld",&cow[i].x,&cow[i].d);
    v1[cow[i].d]++;
    v2[cow[i].d]++;
}
sort(cow+1,cow+n+1,cmp);

再看方法,因为要求最少几头牛,且每个品种至少一头,所以就要尽量减少每一个品种的头数,只要每个种类的头数 > = 1 >=1 >=1就可以了,题目中提示:*照片的成本与规模相当,这就意味着,在一系列照片中的最大和最小 X X X坐标的差距决定了照片的成本。*所以只要把子序列的左边界(l)和右边界®求出来就可以了~~(就是双指针嘛)~~

LL l=1,r=n;
while (v1[cow[l].d]!=1){
   v1[cow[l].d]--;
   ++l;
}//缩减左边界
while (v1[cow[r].d]!=1){
   v1[cow[r].d]--;
   --r;
}//缩减右边界
LL first=cow[r].x-cow[l].x;//得到答案

但是,有时先缩减左边界和先缩减右边界得到的答案不一样~~(你猜我怎么知道的)~~,所以应该重复一次,避免漏掉更小的情况,得到的两个答案中的最小值就是最终答案,因为v1在第一次缩减就已经变了,第二次没法用了,所以在开头就再设一个v2,给第二次用

LL l=1,r=n;
while (v1[cow[l].d]!=1){
    v1[cow[l].d]--;
    ++l;
}//缩减左边界
while (v1[cow[r].d]!=1){
    v1[cow[r].d]--;
    --r;
}//缩减右边界
LL fir=cow[r].x-cow[l].x;//得到第一个答案
l=1;
r=n;
while (v2[cow[r].d]!=1){
    v2[cow[r].d]--;
    --r;
}//缩减右边界
while (v2[cow[l].l]!=1){
    v2[cow[l].d]--;
    ++l;
}//缩减左边界
LL sec=cow[r].x-cow[l].x;//得到第二个答案
printf("%lld",min(fir,sec));

Code:

#include <bits/stdc++.h>
#define LL long long
using namespace std;
LL n, l, r, fir, sec;
struct node{
    LL x, d;
} cow[60005];
bool cmp(node a, node b){
    return a.x < b.x;
}
map<LL, LL> v1,v2;
int main(){
    scanf("%lld", &n);
    for (LL i = 1; i <= n; i++){
        scanf("%lld%lld", &cow[i].x, &cow[i].d);
        v1[cow[i].d]++;
        v2[cow[i].d]++;
    }
    sort(cow + 1, cow + 1 + n, cmp);
    l=1,r=n;
    while (v1[cow[r].d] != 1){
        v1[cow[r].d] -= 1;
        r--;
    }
    while (v1[cow[l].d] != 1){
        v1[cow[l].d] -= 1;
        l++;
    }
    fir = cow[r].x - cow[l].x;
    l = 1, r = n;
    while (v2[cow[l].d] != 1){
        v2[cow[l].d]--;
        l++;
    }
    while (v2[cow[r].d] != 1){
        v2[cow[r].d]--;
        r--;
    }
    sec = cow[r].x - cow[l].x;
    printf("%lld", min(fir, sec));
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值