ICPC第一场网络赛 题解 + 补题
Posted 人形自走Bug生成器
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ICPC第一场网络赛 题解 + 补题相关的知识,希望对你有一定的参考价值。
一些闲话:旅行传送门
A. Busiest Computing Nodes
题意:给你一个含有 \\(k\\) 个节点,编号从 \\(0\\) 至 \\(k-1\\) 的计算集群,以及一组已知到达时间与处理时间的请求(亦从 \\(0\\) 开始编号)。
当每个请求到达时,它会优先进入第 (\\(i\\) % \\(k\\)) 个节点,若当前节点正忙,则根据开放定址法去找下一个空闲节点(如果最终都没能找到空闲的节点,该请求将被忽略)。
现在问你在发送完这组请求后,哪些节点处理的请求数量最多?
题目分析:显然,请求的结束时间(即节点可以被重新启用的时间)= 到达时间 + 处理时间。
先考虑暴力的做法,新请求到来时扫一遍当前节点,如果有节点满足条件(节点内请求的结束时间 \\(\\leq\\) 当前请求的到达时间)就进行更新,时间复杂度约为 \\(O(nk)\\) ,必 \\(T\\)。
这里采取线段树+二分查询优化,时间复杂度 \\(O(nlogk)\\) ,具体看图:
- 线段树维护区间最小值,单点修改,区间查询
- 根据最小值进行二分,为了方便查询我拷贝了一份节点(也可以先查 \\(i\\) ~ \\(k-1\\) ,再查 \\(0\\) ~ \\(i-1\\) ),更新时同时更新两个就好。
- 注意输出格式,行尾无空格(白 PE 六发,真的傻逼)
AC代码:
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int MAXN = 2e5 + 10;
ll k, n, ans[MAXN];
struct obj
{
ll idx, ar, pro;
} a[MAXN];
#define lson k << 1
#define rson k << 1 | 1
struct node
{
int s, t;
ll mn;
} tree[MAXN << 2];
void pushup(int k) { tree[k].mn = min(tree[lson].mn, tree[rson].mn); }
void build(int k, int s, int t)
{
tree[k].s = s, tree[k].t = t;
if (s == t)
return;
int mid = (s + t) >> 1;
build(lson, s, mid);
build(rson, mid + 1, t);
pushup(k);
}
void update(int k, int p, ll x)
{
if (tree[k].s == tree[k].t && tree[k].s == p)
{
tree[k].mn = x;
return;
}
int mid = (tree[k].s + tree[k].t) >> 1;
p <= mid ? update(lson, p, x) : update(rson, p, x);
pushup(k);
}
ll query(int k, int s, int t)
{
if (s <= tree[k].s && tree[k].t <= t)
return tree[k].mn;
int mid = (tree[k].s + tree[k].t) >> 1;
if (t <= mid)
return query(lson, s, t);
else if (s > mid)
return query(rson, s, t);
else
return min(query(lson, s, mid), query(rson, mid + 1, t));
}
int main()
{
scanf("%lld%lld", &k, &n);
for (int i = 1; i <= n; i++)
scanf("%lld%lld", &a[i].ar, &a[i].pro), a[i].idx = i - 1;
build(1, 1, 2 * k);
for (int i = 1; i <= n; i++)
{
ll st = a[i].idx % k + 1, ed = st + k - 1;
int l = st, r = ed;
while (l < r)
{
int mid = (l + r) >> 1;
if (query(1, l, mid) <= a[i].ar)
r = mid;
else
l = mid + 1;
}
ll dest = l;
if (query(1, dest, dest) <= a[i].ar)
{
update(1, dest, a[i].ar + a[i].pro);
if (dest <= k)
update(1, dest + k, a[i].ar + a[i].pro), ans[dest - 1]++;
else
update(1, dest - k, a[i].ar + a[i].pro), ans[dest - k - 1]++;
}
}
ll mx = 0;
for (int i = 0; i < k; i++)
mx = max(mx, ans[i]);
vector<int> realans;
for (int i = 0; i < k; i++)
if (ans[i] == mx)
realans.push_back(i);
for (int i = 0; i < realans.size() - 1; i++)
printf("%d ", realans[i]);
printf("%d\\n", realans[realans.size() - 1]);
return 0;
}
F. Land Overseer
题意:给你两个圆心分别为 \\((a,b)\\) 与 \\((2a,0)\\) 的圆 \\(A\\) 、 \\(B\\) ,半径均为 \\(r\\) 的圆,现从原点出发,问先经过圆 \\(A\\) 再经过圆 \\(B\\) 的最短路径是多少?
题目分析:分两种情况讨论,具体看图和代码:
AC代码:
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int T;
ll a, b, R;
int main()
{
scanf("%d", &T);
for (int i = 1; i <= T; i++)
{
scanf("%lld%lld%lld", &a, &b, &R);
double ans = 0;
if ((a > R && b > R) || (a <= R))
ans = sqrt(4.0 * a * a + 4.0 * (b - R) * (b - R)) - 1.0 * R;
else if (a > R && b <= R)
ans = 2.0 * a - 1.0 * R;
printf("Case #%d: %.2lf\\n", i, ans);
}
return 0;
}
I. Neighborhood Search
题意:给你一个序列 \\(S\\) 和一个数 \\(A\\) ,找出序列中所有与 \\(A\\) 的差值 \\(\\leq r\\) 的元素,降序输出。
题目分析:签到题,降序排列后 \\(O(n)\\) 扫一遍就好,难点主要在处理输入数据上。
AC代码:
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int MAXN = 1e5 + 10;
ll S[MAXN], len, ans;
int main()
{
while (scanf("%lld", &S[++len]) != EOF)
;
len -= 3;
sort(S + 1, S + 1 + len, greater<ll>());
ll A = S[len + 1], r = S[len + 2];
for (int i = 1; i <= len; i++)
if (abs(S[i] - A) <= r)
printf("%lld ", S[i]), ++ans;
if (!ans)
printf("\\n");
return 0;
}
K. Segment Routing
题意:模拟题,给你一张有向图,每次询问从节点 \\(i\\) 开始按指定方向走最终到达的点。
题目分析:阅读理解+模拟,跟着题意来就好,越界就判定丢包。
AC代码:
#include <bits/stdc++.h>
using ll = long long;
using namespace std;
const int maxn = 1e5 + 5;
std::vector<int> e[maxn];
int main()
{
int T;
scanf("%d", &T);
for (int cas = 1; cas <= T; cas++)
{
printf("Case #%d: \\n", cas);
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
e[i].clear();
for (int i = 1; i <= n; i++)
{
int d;
scanf("%d", &d);
for (int j = 1; j <= d; j++)
{
int v;
scanf("%d", &v);
e[i].push_back(v);
}
}
for (int i = 1; i <= m; i++)
{
int u, l;
scanf("%d%d", &u, &l);
int flag = 1;
for (int j = 1; j <= l; j++)
{
int v;
scanf("%d", &v);
if (!flag)
continue;
if (e[u].size() < v)
{
puts("Packet Loss");
flag = 0;
continue;
}
u = e[u][v - 1];
}
if (flag)
printf("%d\\n", u);
}
}
return 0;
}
以上是关于ICPC第一场网络赛 题解 + 补题的主要内容,如果未能解决你的问题,请参考以下文章
日常补题——ICPC网络赛上海站第二题B Light bulbs