AtCoder Beginner Contest 051

A
题意:
给一个逗号分割的字符串,改成空格分隔输出。

    std::string s;
    std::getline(std::cin, s);
    for (auto &u : s) if (u == ',') u = ' ';
    std::cout << s << "\n";

B
题意:
给一个 \(K, S\) 。询问满足 \(0 \leq \{X, Y, Z\} \leq K, X + Y + Z = S\)\(|(X, Y, Z)|\)
\(2 \leq K \leq 2500, 0 \leq S \leq 3K\)

题解:

\(2500^{3}\) 能做吗?不能。但是可以枚举两个,算一个。 \(2500^{2}\) 能做吗?能。
注意没有规定顺序。

    int K, S; std::cin >> K >> S;
    int cnt = 0;
    for (int i = 0; i <= K; i++) {
        for (int j = 0; j <= K; j++) {
            int z = S - i - j;
            cnt += 0 <= z && z <= K;
        }
    }
    std::cout << cnt << "\n";

考虑规定 \(0 \leq X \leq Y \leq Z \leq K, X + Y + Z = S\) ,询问 \(|(X, Y, Z)|\) 。则计算类似:

    int cnt = 0;
    for (int i = 0; i <= K; i++) {
        for (int j = i; j <= K; j++) {
            int z = S - i - j;
            cnt += j <= z && z <= K;
        }
    }

甚至可以 \(O(S)\)

枚举 \(Z \in [0, S]\) ,得 \(L = S - Z = X + Y\)

尝试 \(O(1)\) 回答有 \(0 \leq X \leq Y \leq Z, X + Y = L\) 的二元组数。

\[\begin{aligned} &\sum [L - Z + P \leq Z - P] \ s.t.\ L - Z + P \leq Z - P \\ &= \sum_{P = 0}^{\lfloor \frac{2Z - L}{2} \rfloor} 1 \\ \end{aligned} \]

考虑规定: \(X \in [l_X, r_X], Y \in [l_Y, r_Y], Z \in [l_Z, r_Z], X + Y + Z \geq S\) ,询问 \(|(X, Y, Z)|\)

还是可以 \(O(S)\) 做。

依然枚举 $Z \in [l_Z, r_Z] $, 得 \(L = X + Y \geq S - Z\)

怎么求 \(X + Y = L \ s.t.\ X \in [l_X, r_x], Y \in [l_Y, r_Y]\)\(|(X, Y)|\) ?不容易直接算了(不是不能算)。

先说明这个东西是好算的,假设我们能提前求出上述的 \(f(L) = |(X, Y)| \ s.t.\ X + Y = L\)

再提前对 \(f\) 求前缀和 \(g\)\(g(L) = |(X, Y) \ s.t.\ X + Y \leq L |\) 。时间复杂度 \(O(S)\)

那么容斥 \(g(S) - g(L - 1)\) 即为 \(|(X, Y)| \ s.t. L = X + Y \geq S - Z\)

问题收束,\(f(L)\) 怎么求?一个好的性质是定义域连续。

for \(X^{'} \in [l_X, r_X]\) ,于是 \([X^{'} + l_Y, X^{'} + r_Y]\) 的位置都会被计算加 \(1\) 的贡献。

通过差分可以 \(O(S)\) 算出 \(f\) 数组的差分数组,求前缀和得到 \(f\)

总时间复杂度是 \(O(S)\)

C
题意:
海豚居住在二维笛卡尔坐标系上,坐标反向是从左下角往右上角看。海豚每一步可以向上、下、左、右走 \(1\) 的距离。

海豚一开始在 \((sx, sy)\) 点,然后会走到 \((tx, ty)\) ,然后回到 \((sx, sy)\)\(sx < tx, sy < ty\)

继续重复一次上述步骤。

除了 \((sx, sy)\)\((tx, ty)\) ,海豚不能经过一次坐标多次。

询问任意一条路径通路,边的输出方式为“当前位置的下一步方向”。

比如:sx = 0, sy = 0, tx = 1, ty = 2 。一个答案为:UURDDLLUUURRDRDDDLLU 。

题解:

路径其实好找。

第一轮走任意两条除了端点外不相交的曼哈顿距离最短的路径,即在 \((sx, sy), (tx, ty)\) 确定的矩形 \(A\) 中选两条。

第一轮不妨贴着矩形 \(A\) 的边走。

第二轮无法在 \(A\) 中选路径,因为 \((sx, sy)\) 的两个度和 \((tx, ty)\) 的两个度被用完了。所以再往外一圈的矩形 \(B\) 中走曼哈段最短距离的路径。

第二轮不妨也贴着矩形 \(B\) 的边走。考虑在 \(B\) 内但不在 \(A\) 内的曼哈顿距离最短路径很显然。

    int sx, sy, tx, ty; std::cin >> sx >> sy >> tx >> ty;
    std::string ans = "";
    ans += std::string(tx - sx, 'R');
    ans += std::string(ty - sy, 'U');
    
    ans += std::string(tx - sx, 'L');
    ans += std::string(ty - sy, 'D');
    
    ans += 'D';
    ans += std::string(tx - sx + 1, 'R');
    ans += std::string(ty - sy + 1, 'U');
    ans += 'L';

    ans += 'U';
    ans += std::string(tx - sx + 1, 'L');
    ans += std::string(ty - sy + 1, 'D');
    ans += 'R';

    std::cout << ans << "\n";

D
题意:

给一个 \(N\) 个点 \(M\) 条边的无向连通带权图,保证没有自环和重边。

\(i(1 \leq M)\) 条边连接节点 \(a_i\) 和 节点 \(b_i\) ,权值为 \(c_i\)

给一个 \(N, (N \leq 100)\) 个点 \(M\) 条边的无向带权连通图,没有自环和重边。第 \(i\) 条边连接点 \(a_i\) 和点 \(b_i\) 且距离为 \(c_i, (0 \leq c_i \leq 1000)\) 。找到不存在于任何最短路径中的边,计算它们的数量。

找到一类边的数量,满足这类边不在任意两个节点的可能的最短路径中。

连通图:任意节点互相可达。

\(1 \leq N \leq 100, N - 1 \leq M \leq min(\frac{N(N-1)}{2}, 1000)\)

\(1 \leq a_i, b_i, \leq N, 1 \leq c_i \leq 1000\)

题解:

和任意两点的最短路有关,先 \(O(n^{2})\) 冲个 Floyd 求出任意两点的最短路 \(dist_{u, v}\)

考虑一条无向边 \(e(a, b)\) ,如果在某两个点 \(u, v\) 的最乱路上,一定有 \(dist_{u, a} + w(a, b) + dist_{b, v} = dist{u, v}\)\(dist_{u, b} + w(b, a) + dist_{a, v} = dist{u, v}\)

可以枚举每一条边 \(e(a, b)\) ,枚举两个点 \(u, v(\{u, v\} \cap \{a, b\} = \emptyset)\) 。若 \(e(a, b)\) 不在任意 \((u, v)\) 的最短路上,则 \(e(a, b)\) 加入解集 \(\mathbb{S}\) 。最终 \(|\mathbb{S}|\) 是答案。时间复杂度 \(O(n^{2} m)\)

事实上,任意两个点 \(u, v\) 的某条最短路径 \(r\) ,去除一个端点后依旧是一条最短路径。否则可以在 \(u, v\) 间构造出一条比 \(r\) 更短的路径。

这意味着任意两个点 \(u, v\) 的某条最短路径,首位去除若干连续个点后依旧一条最短路径。

所以,枚举任意一条边 \(e(a, b)\) ,只用枚举一个点 \(u(u \neq a, b)\) 。检查 \(u\)\(a\)\(b\) 的最短路是否经过 \(e(a, b)\) 即可。

当任意点 \(u\)\(a\)\(b\) 的最短路都不经过过 \(e(a, b)\) ,则 \(e(a, b)\) 加入解集 \(S\)

chek 所有边的时间复杂度为 \(O(m n)\)

于是总时间复杂度为 \(O(n^{3} + n m)\)

    int N, M; std::cin >> N >> M;
    std::vector<std::vector<int> > w(N + 1, std::vector<int>(N + 1));
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= N; j++) {
            if (i == j) w[i][j] = 0;
            else w[i][j] = inf;
        }
    }
    std::vector<std::array<int, 2> > e(M + 1, {0, 0});
    for (int i = 1; i <= M; i++) {
        int u, v, wight; std::cin >> u >> v >> wight;
        e[i] = {u, v};
        w[u][v] = std::min(w[u][v], wight);
        w[v][u] = std::min(w[v][u], wight);
    }
    std::vector<std::vector<int> > dist = w;
    for (int k = 1; k <= N; k++) {
        for (int i = 1; i <= N; i++) {
            for (int j = 1; j <= N; j++) {
                if (dist[i][k] != inf && dist[k][j] != inf && dist[i][k] + dist[k][j] < dist[i][j]) {
                    dist[i][j] = dist[i][k] + dist[k][j];
                }
            }
        }
    }
    int cnt = 0;
    for (int i = 1; i <= M; i++) {
        int ok = 0;
        for (int j = 1; j <= N; j++) {
            ok |= (dist[j][e[i][0]] + w[e[i][0]][e[i][1]] == dist[j][e[i][1]] || dist[j][e[i][1]] + w[e[i][1]][e[i][0]] == dist[j][e[i][0]]);
        }
        if (!ok)
            cnt += 1;
    }
    std::cout << cnt << "\n";
posted @ 2023-03-16 00:09  03Goose  阅读(30)  评论(0)    收藏  举报