CH0805 防线(秦腾与教学评估)
CH0805 防线(秦腾与教学评估)
http://noi-test.zzstep.com/contest/0x08「基本算法」练习/0805 防线(秦腾与教学评估)
分析
题目中明确指出只有一个位置可能是奇数,很容易想到计算防具数目的前缀和,在防具数目为奇数的位置之前的前缀和均为偶数,在该位置及之后的前缀和均为奇数。前缀和满足>单调性<,故可以用二分答案的方法来进行验证。
但若直接暴力地计算每个位置的前缀和,显然会超时。我们可以在二分的时候再进行计算,而且只需要计算二分出来的位置的前缀和(扫描每一个防具段,然后将对前缀和的贡献累加),这样大大减少了运算量,时间复杂度为,总时间复杂度为
实现
//
// main.cpp
// daily
//
// Created by 闫润邦 on 2021/8/27.
// Copyright © 2021 闫润邦. All rights reserved.
//
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define ll long long
using namespace std;
const int maxn = 2e5 + 10;
int T,n;
struct NODE
{
int s , e , d;
}ord[maxn];
ll max(ll x, ll y)
{
return x > y ? x : y;
}
ll min(ll x,ll y)
{
return x < y ? x : y;
}
int main(int argc, const char * argv[])
{
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i = 1; i <= n; i++)
scanf("%d%d%d" , &ord[i].s , &ord[i].e , &ord[i].d);
ll l = 1, r = 1ll<<31;
while(l < r)
{
int cnt = 0;
ll mid = (l + r) / 2;
for(int i = 1; i <= n; i++)
if(ord[i].s <= mid)
cnt += ( min(mid , ord[i].e) - ord[i].s ) / ord[i].d + 1;
if(cnt & 1)
r = mid;
else
l = mid + 1;
}
if(l == 1ll<<31)
printf("There's no weakness.\n");
else
{
int ans = 0;
for(int i = 1; i <= n; i++)
if(l >= ord[i].s && (l - ord[i].s) % ord[i].d == 0)
ans++;
printf("%lld %d\n",l,ans);
}
}
return 0;
}
总结
二分答案很好想到,本题难点在于计算前缀和的方法,在二分的过程中计算单点的前缀和,而不是常规的“先计算前缀和,再二分”。
转换思路很重要!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现