我解决的:A、I、B。
没看的:无。
旁观的:C、E、M、K、J、L、H。
看了但没做出来的:D、F、G。
A Accurate Movement
简单题,略。
M Managing Difficulties
简单题,略。
K King’s Children
一个不是很困难的构造,略。
E Equidistant
题意;给定一个树,有 个关键点,问树上有无某个点使得这个点到每一个关键点的距离相同。
把所有关键点放进队列里 BFS,对每个点统计离其最近的关键点个数即可。
#include <bits/stdc++.h>
using namespace std;
int n, m;
vector<int> G[200005];
queue<int> q;
int cnt[200005] = {0}, dis[200005];
int main(){
scanf("%d%d", &n, &m);
for (int i = 1, u, v; i < n; ++i){
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
memset(dis, 0x3f, sizeof(dis));
for (int i = 1, t; i <= m; ++i){
scanf("%d", &t);
q.push(t), cnt[t] = 1, dis[t] = 0;
}
while (!q.empty()){
int h = q.front();
q.pop();
for (int x: G[h]){
if (dis[x] == dis[h] + 1) cnt[x] += cnt[h];
else if (dis[x] > dis[h] + 1){
dis[x] = dis[h] + 1;
cnt[x] = cnt[h];
q.push(x);
}
}
}
for (int i = 1; i <= n; ++i)
if (cnt[i] == m){
printf("YES\n%d\n", i);
return 0;
}
printf("NO\n");
return 0;
}
H High Load Database
题意:给定一个序列,序列中数的和不超过 。多次询问,每次给定 ,要将序列划分成多个段,每段的和不超过 ,求最少段数。
对单个 ,可以前缀和加上二分处理。但是多个 ,每个 都这么做会 TLE。
又,对于一个 ,序列最多被划分成 份。因此把所有的 存下来,对不重复的 都做一次即可。这样的时间复杂度和调和级数有关。
I Ideal Pyramid
题意:给定平面上 个柱子,每个柱子有一定高度。现在要造一个形状为四面体的金字塔,塔面和平面成 45 度,塔尖在平面的投影点要是整点,塔高要为整数。所有柱子都必须在金字塔下方。问金字塔的最小高度。
由相似三角形可知,金字塔 需满足对于所有柱子 ,有 。
转化一下得到 。于是我们可以分别考虑 坐标和 坐标。
先考虑
坐标。考虑把绝对值解开,得到
对于这个优化问题,我们要先优化
。对于这种形式的问题,
最优值要取
和
的中点。由于本题的限制,中点为小数时,要转而考虑其两边的整点。
对于 类似。然后再对每种可能的情况,算一下对应的 ,取最小值即可。
B Bad Treap
题意:有一个笛卡尔树,对于权重为大根堆,对于值为搜索树。其值为 时权重为 。要求构造一个有 个点的这样的笛卡尔树,使得其高度恰为 。
这题有两个主要想法:构成一条链或者构成一个交叉序列,如 。这样高度都是 。
对于构成链,可以找很多数然后对于 求 LIS,但是可能 TLE。
另一个可以通过的做法是把 分成 个区间,要构造第 个节点时,从 的中点开始,不断加 ,直到其与某个最近的正整数(即取 ceil 或者 floor)之间相差小于 ,且该整数比上一个节点的值要大为止。
#include <bits/stdc++.h>
using namespace std;
int n;
int main(){
scanf("%d", &n);
double pi = acos(-1), pi2 = pi * 2, pihf = pi * 0.5;
double piece = pi / n, eps = piece * 0.5;
int k = 0, i = 0;
for (i = 0; i < n; ++i){
double st = -pihf + piece * i + eps;
while (k < 100000000){
double kk = st + k * pi2;
double yy1 = ceil(kk), yy2 = floor(kk);
if (fabs(kk - yy1) < eps){
int res = (int)yy1;
printf("%d\n", res);
break;
}
if (fabs(kk - yy2) < eps){
int res = (int)yy2;
printf("%d\n", res);
break;
}
++k;
}
// 保证下一个节点的值比上一个大
k += 2;
}
return 0;
}
还有一个非常简单的做法:找一个很小的 ,使得 ,在 从 递增到很大时其也仍然递增。一个选择是 ,其等于 加上一个极小的数 。
由于 ,而 ,因此根据 的奇偶性和单调性, 从 开始枚举就没有问题了。
对于构成交叉序列,目前我还没有找到能对付 的做法,只能应付 级别的数据。
J Just the Last Digit
题意:有一个拓扑图,边只能从编号小的向大的连。设 为从 到 的方案数,给定所有 的 ,求出原图。保证有解。
考虑从后向前构造。从大到小枚举 ,然后从小到大枚举 。如果按照已经构造好的图 和要求不符,那么就表明 间有边(不然没有其他从 到 的方法了)。连上这条边,并更新 的 即可。
C Cross-Stitch
待补。。。
L Lengths and Periods
待补。。。
D Double Palindrome
待补。。。
F Foreach
待补。。。
G Golf Time
待补。。。