「CF1101F」Trucks and Cities
题意描述
有
传送门
思考&做法
step 1
先来思考暴力,二分答案,然后check所有车,时间
到这,就有了多个分支,有大佬改换思路用
step 2
苦思冥想的时候,yangbaich给了我一个思路:在二分
step3
本来以为能做了,只不过每次要加边,倍增表只能静态,那怎么做呢?如果没有「CF13E」Holes的经验其实很难想到动态修改的跳表。思路就是按索引分块,对于每个元素维护一个
在查询的时候,跳的过程中每次check当前
概括
二分答案,将卡车和预处理的
总时间复杂度
solution
/*
address:https://codeforces.com/problemset/problem/1101/F
AC 2025/1/21 11:40
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 405, M = 2.5e5 + 5;
const LL INF = 1e18;
int a[N];
int n, m;
struct truck {
int s, f, c, r;
bool operator < (const truck& o)const { return c > o.c; }
}c[M];
struct node {
int x, y;
LL c;
bool operator < (const node& o)const { return c > o.c; }
}e[N * N];
int siz, blk;
int bel[N], nxt[N], jump[N], step[N], L[N], R[N];
inline void change(int id, int x) {
nxt[id] = x;
// printf("change %d -> %d ", id, x);
for (int i = id;i >= L[bel[id]];i--)
if (nxt[i] > R[bel[i]]) step[i] = 1, jump[i] = nxt[i];
else step[i] = step[nxt[i]] + 1, jump[i] = jump[nxt[i]];
// printf("step:%d\n", step[id]);
}
inline int lift(int id, int x) {
while (true) {
if (x < step[id]) break;
x -= step[id];
id = jump[id];
// printf("%d ", id);
}
for (int i = 1;i <= min(x, siz);i++) id = nxt[id];
// puts("");
return id;
}
inline bool check(LL v) {
// printf("%lld:\n", v);
int t = 0;
for (int i = 1;i <= n;i++)
for (int j = i + 1;j <= n;j++)
e[++t] = { i, j, v / (a[j] - a[i]) };
sort(e + 1, e + t + 1);
// for (int i = 1;i <= t;i++) printf("%d %d %lld\n", e[i].x, e[i].y, e[i].c);
for (int i = 1;i <= n;i++) nxt[i] = jump[i] = i, step[i] = N;
int j = 1;
for (int i = 1;i <= m;i++) {
// printf("truck %d:", i);
while (e[j].c >= c[i].c && j <= t) {
change(e[j].x, e[j].y);
j++;
}
// puts("");
int u = lift(c[i].s, c[i].r + 1);
if (u < c[i].f) return false;
}
return true;
}
int main() {
scanf("%d%d", &n, &m);
siz = sqrt(n);
blk = (n + siz - 1) / siz;
for (int i = 1;i <= n;i++) scanf("%d", &a[i]);
for (int i = 1;i <= n;i++) bel[i] = (i + siz - 1) / siz;
for (int i = 1;i <= blk;i++) L[i] = (i - 1) * siz + 1, R[i] = min(i * siz, n);
for (int i = 1;i <= m;i++) scanf("%d%d%d%d", &c[i].s, &c[i].f, &c[i].c, &c[i].r);
sort(c + 1, c + m + 1);
LL l = 1, r = INF, v = INF;
while (l <= r) {
LL mid = l + r >> 1;
if (check(mid)) r = mid - 1, v = mid;
else l = mid + 1;
}
printf("%lld", v);
return 0;
}
总结
不知道为什么,与yangbaich做题总能做出一些奇奇怪怪的做法,只不过这样也有益于拓展思维,希望后面不知只是按题解所说去做,能多有一些自己的思考并实践。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现