【解题总结】North-Western Russia Regional Contest 2019(Codeforces Gym 102411)

我解决的: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

题意;给定一个树,有 m m 个关键点,问树上有无某个点使得这个点到每一个关键点的距离相同。

把所有关键点放进队列里 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

题意:给定一个序列,序列中数的和不超过 1 0 6 10^6 。多次询问,每次给定 t t ,要将序列划分成多个段,每段的和不超过 t t ,求最少段数。

对单个 t t ,可以前缀和加上二分处理。但是多个 t t ,每个 t t 都这么做会 TLE。

又,对于一个 t t ,序列最多被划分成 O ( 1 0 6 t ) O\left(\frac{10^6}{t}\right) 份。因此把所有的 t t 存下来,对不重复的 t t 都做一次即可。这样的时间复杂度和调和级数有关。

I Ideal Pyramid

题意:给定平面上 n n 个柱子,每个柱子有一定高度。现在要造一个形状为四面体的金字塔,塔面和平面成 45 度,塔尖在平面的投影点要是整点,塔高要为整数。所有柱子都必须在金字塔下方。问金字塔的最小高度。

由相似三角形可知,金字塔 ( x , y , h ) (x, y, h) 需满足对于所有柱子 i i ,有 max { x x i , y y i } h h i \max\left\lbrace |x-x_i|, |y-y_i|\right\rbrace \le h - h_i

转化一下得到 i , h x x i + h i h y y i + h i \forall i, h \ge |x-x_i| + h_i \wedge h \ge |y-y_i| + h_i 。于是我们可以分别考虑 x x 坐标和 y y 坐标。

先考虑 x x 坐标。考虑把绝对值解开,得到
h = min max 1 i n { x ( x i h i ) , ( x i + h i ) x } h = \min \max_{1\le i \le n}\left\lbrace x- (x_i - h_i), (x_i + h_i) - x \right\rbrace
对于这个优化问题,我们要先优化 x x 。对于这种形式的问题, x x 最优值要取 min 1 i n ( x i h i ) \min_{1 \le i \le n}(x_i - h_i) max 1 i n ( x i + h i ) \max_{1 \le i \le n}(x_i + h_i) 的中点。由于本题的限制,中点为小数时,要转而考虑其两边的整点。

对于 y y 类似。然后再对每种可能的情况,算一下对应的 h h ,取最小值即可。

B Bad Treap

题意:有一个笛卡尔树,对于权重为大根堆,对于值为搜索树。其值为 v v 时权重为 sin ( v ) \sin(v) 。要求构造一个有 n n 个点的这样的笛卡尔树,使得其高度恰为 n n

这题有两个主要想法:构成一条链或者构成一个交叉序列,如 1 , 5 , 2 , 4 , 3 1, 5, 2, 4, 3 。这样高度都是 n n

对于构成链,可以找很多数然后对于 sin \sin 求 LIS,但是可能 TLE。

另一个可以通过的做法是把 ( π 2 , π 2 ) \left( -\frac{\pi}{2}, \frac{\pi}{2} \right) 分成 n n 个区间,要构造第 i i 个节点时,从 ( π 2 + ( i 1 ) π n , π 2 + i π n ) \left( -\frac{\pi}{2} + \frac{(i-1)\pi}{n}, -\frac{\pi}{2} + \frac{i\pi}{n}\right) 的中点开始,不断加 2 π 2\pi ,直到其与某个最近的正整数(即取 ceil 或者 floor)之间相差小于 π 2 n \frac{\pi}{2n} ,且该整数比上一个节点的值要大为止。

#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;
}

还有一个非常简单的做法:找一个很小的 sin ( x ) \sin(x) ,使得 sin ( k x ) \sin(kx) ,在 k k 1 1 递增到很大时其也仍然递增。一个选择是 x = 710 x=710 ,其等于 113 2 π 113 \cdot 2\pi 加上一个极小的数 ϵ \epsilon

由于 50000 ϵ > π 2 50000\epsilon > \frac{\pi}{2} ,而 25000 ϵ < π 2 25000\epsilon < \frac{\pi}{2} ,因此根据 sin \sin 的奇偶性和单调性, k k 25000 -25000 开始枚举就没有问题了。

对于构成交叉序列,目前我还没有找到能对付 n = 50000 n=50000 的做法,只能应付 n = 10000 n=10000 级别的数据。

J Just the Last Digit

题意:有一个拓扑图,边只能从编号小的向大的连。设 f ( i , j ) f(i, j) 为从 i i j j 的方案数,给定所有 i , j i, j f ( i , j ) m o d 10 f(i, j) \bmod 10 ,求出原图。保证有解。

考虑从后向前构造。从大到小枚举 i i ,然后从小到大枚举 j > i j>i 。如果按照已经构造好的图 f ( i , j ) f(i, j) 和要求不符,那么就表明 i , j i, j 间有边(不然没有其他从 i i j j 的方法了)。连上这条边,并更新 k > j k>j f ( i , k ) f(i, k) 即可。

C Cross-Stitch

待补。。。

L Lengths and Periods

待补。。。

D Double Palindrome

待补。。。

F Foreach

待补。。。

G Golf Time

待补。。。

猜你喜欢

转载自blog.csdn.net/zqy1018/article/details/108282801