返回顶部

AcWing - 120 - 防线 = 二分 + 前缀和

https://www.acwing.com/problem/content/122/

题意:给2e6个区间,每个区间三个数Si,Ei,Di,表示在[Si,Ei]范围内,距离Si每隔Di都有一个装备,范围是[0,INT_MAX]。

题目保证有奇数个装备的点至多一个,要找这个点。

题解说,要找这种只有一个的奇数点,想到前缀和是非常自然的(现在学会了之后就非常自然)。

那么二分这个位置求前缀和就可以了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int n, S[200005], E[200005], D[200005];

int query(int x, int i) {
    //询问x位置及其之前有多少个防具i
    if(x < S[i])
        return 0;
    if(D[i] == 0)
        return 1;
    if(x > E[i])
        x = E[i];
    return (x - S[i]) / D[i] + 1;
}

int sum(int x) {
    //询问x位置及其之前的防具前缀和是不是奇数
    int s = 0;
    for(int i = 1; i <= n; ++i) {
        s += query(x, i);
    }
    //printf("x=%d sum=%d\n", x, s);
    return s;
}

int check(int x) {
    return (sum(x) & 1);
}

int bs() {
    int l = 0, r = INT_MAX;
    while(1) {
        int m = l + ((r - l) >> 1);
        if(l == m) {
            if(check(l))
                return l;
            else if(check(r))
                return r;
            else
                return -1;
        }
        if(check(m))
            r = m;
        else
            l = m + 1;
    }
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int T;
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) {
            scanf("%d%d%d", &S[i], &E[i], &D[i]);
        }
        int ans = bs();
        if(ans == -1)
            puts("There's no weakness.");
        else
            printf("%d %d\n", ans, sum(ans) - sum(ans - 1));
    }
}
posted @   Inko  阅读(117)  评论(0编辑  收藏  举报
编辑推荐:
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
· .NET 适配 HarmonyOS 进展
阅读排行:
· 用 DeepSeek 给对象做个网站,她一定感动坏了
· DeepSeek+PageAssist实现本地大模型联网
· 手把手教你更优雅的享受 DeepSeek
· 腾讯元宝接入 DeepSeek R1 模型,支持深度思考 + 联网搜索,好用不卡机!
· 从 14 秒到 1 秒:MySQL DDL 性能优化实战
点击右上角即可分享
微信分享提示