USACO历年白银组真题解析 | 2023年2月Cow-libi

该篇文章详细描述了解决一道关于奶牛清白判断的算法问题,使用C++实现,主要运用了二分查找技术。
摘要由CSDN通过智能技术生成

学习C++从娃娃抓起!记录下USACO(美国信息学奥赛)备考白银组别比赛学习过程中的题目,记录每一个瞬间。

附上汇总贴:USACO历年白银组真题解析 | 汇总-CSDN博客


【题目描述】

有 g 处抓握,第 i 处抓握如 (xi,yi,ti)(−10^9≤xi,yi≤10^9,0≤ti≤10^9),表示 ti 时刻 (xi,yi) 有一处抓握,FJ 抓到了 n 头嫌疑奶牛,每头奶牛都提供了如 (xj,yj,tj) 的证词,表示它 tj 时刻在 (xj,yj),一头奶牛一个单位时间可以移动一个单位距离,奶牛可以洗脱自己的清白,当且仅当它没有足够的时间作出所有的抓握,即,只要它没有足够的时间从它提供的证词的时刻到达随便一个抓握处,它就是清白的。

问有多少奶牛是清白的?

【输入】

第一行输入 g,n

接下来 g 行每行三个整数 xi,yi,ti 表示一处抓握。

接下来 n 行每行三个整数 xj,yj,tj 表示一个证词。

【输出】

一行一个整数表示清白的牛的个数。

【输入样例】

2 4
0 0 100
50 0 200
0 50 50
1000 1000 0
50 0 200
10 0 170

【输出样例】

2

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long  // 因为题目中计算后会超int,所以全部修改为long long
int G, n, ans;
struct node {
    int x, y, t;
    bool operator < (node other) {  // 后面用到sor排序,重载"<"
        return t < other.t;
    }
}g[100005];
signed main()  // 前面有define,所以这里改为signed
{
    cin >> G >> n;  // 输入G和n
    for (int i=1; i<=G; i++) {  // 输入G个吃草的点
        cin >> g[i].x >> g[i].y >> g[i].t;
    }
    sort(g+1, g+G+1);  // 所有的点按照从小到大排序
    int cowx, cowy, cowt;
    for (int i=1; i<=n; i++) {  // 输入每只奶牛的证词
        cin >> cowx >> cowy >> cowt;
        int res=0;  // 定义二分答案
        if (cowt<g[1].t) {  // 如果cowt时刻小于g[1].t
            if ((g[1].x-cowx)*(g[1].x-cowx)+(g[1].y-cowy)*(g[1].y-cowy) > (g[1].t-cowt)*(g[1].t-cowt)) {  // 如果它没有足够的时间到达g[1]
                ans++;  // 就是无辜的
            }
        } else if (cowt>g[G].t) {  // 如果cowt的时刻大于g[G].t
            if ((g[G].x-cowx)*(g[G].x-cowx)+(g[G].y-cowy)*(g[G].y-cowy) > (g[G].t-cowt)*(g[G].t-cowt)) {  // 如果它没有足够的时间到达g[G]
                ans++;  // 也是无辜的
            }
        } else {
            int l = 1, r = G;
            while (l<=r) {  // 二分答案模板
                int mid = (l+r)/2;
                if (g[mid].t<cowt) {  // g[mid].t小于cowt时(其他模板代码固定,可以开调试观察这里的结果)
                    res = mid;  // 就更新res
                    l = mid+1;  // 然后增加l,找到最大的l
                } else {  // 否则
                    r = mid-1;  // 减少r
                }
            }
            bool innocent = false;  // 定义标记位
            if ((g[res].x-cowx)*(g[res].x-cowx) + (g[res].y-cowy)*(g[res].y-cowy) > (g[res].t-cowt)*(g[res].t-cowt)) {  // 如果无法到res这个点
                    innocent = true;  // 修改标记位
            }
            if ((g[res+1].x-cowx)*(g[res+1].x-cowx) + (g[res+1].y-cowy)*(g[res+1].y-cowy) > (g[res+1].t-cowt)*(g[res+1].t-cowt)) {  // 如果无法到res+1这个点
                innocent = true;  // 修改标记位
            }
            ans += innocent;  // 只要有一个吃草点无法到达,就是无辜的
        }
    }
    cout << ans << endl;  // 输出无辜的奶牛数量
    return 0;
}

【运行结果】

2 4
0 0 100
50 0 200
0 50 50
1000 1000 0
50 0 200
10 0 170
2
  • 11
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值