SSL-OI夏日合宿 2020.08.23 A组

打开知乎: 如何接受自己的平凡? 三道水题, ZZY已AK. 而我, 连100分都拿得难看. A 失落 题意 给出一个数的集合, 问子集求和不能得到的最小的数是多少? n100000n\leq100000, 1ai1091 \leq ai \leq 10^9 故事 写这题确实挺失落的. 肯定是一道结论题, 所以我选择打部分分. 人还是要有志向的, 所以就想了一个钟, 推出了一个错误的结论. 明明结论那么显然 虽然后面艰难地改过来了: 设$

打开知乎: 如何接受自己的平凡? 三道水题, ZZY已AK. 而我, 连100分都拿得难看.

A 失落

题意

给出一个数的集合, 问子集求和不能得到的最小的数是多少?

n100000n\leq100000, 1ai1091 \leq a_i \leq 10^9

故事

写这题确实挺失落的.

肯定是一道结论题, 所以我选择打部分分. 人还是要有志向的, 所以就想了一个钟, 推出了一个错误的结论. (明明结论那么显然)

虽然后面艰难地改过来了: 设ansans为目前最小不能达成的数字, 那么ans1ans-1就是最大能达成的数字. 我们升序加入数字: 现在加入一个数xx, 若有小于xx的数没有达成, 那么加入xx后, 加入xx后面的数, 都不可能达成那个数, 所以此时ansans即为答案.

ansxans\geq x, 显然将[0,ans)[0,ans)内的数分别加上xx, 可以达成的数集变为了[0,ans+x)[0,ans+x), 如此更新ansans即可.

#define MXN (1000000)

#include <stdio.h>

#include <algorithm>

long long n, a[MXN], ans = 1;

signed main() {
#ifndef ONLINE_JUDGE
    freopen("A.in", "r", stdin);
#endif

    scanf("%lld", &n);
    for (int i = 0; i < n; ++i)
        scanf("%lld", &a[i]);

    std::sort(a, a + n);

    for (int i = 0; i < n && ans >= a[i]; ++i)
        ans += a[i];

    printf("%lld", ans);

    return 0;
}

B 最优路线

题意

给一张nnmm边的图, 有边权点权. 路径值的计算方法是: 路径上最大点权乘上路径上最大边权. 问: 所有点对之间的路径最小值是多少?

n500n\leq500, 边权点权和不超过10910^9. (要开long long)

题解

没有故事, 我觉得Floyd很麻烦还必挂就没打了. 于是:

正解是魔改Floyd.

考虑Floyd是逐渐加点的过程, 我们按点权升序加点, 这样每次加入后这个点必是当前路径中(除开两个端点)最大值, 不用考虑路径中其他点的影响. 如果加入这个点后使边权最大值变小, 则尝试更新答案(最大边权乘上当前点权和两个端点点权的最大值). 否则不更新, 因为我们升序枚举了点权.

#include <stdio.h>
#include <string.h>

#include <algorithm>
#include <queue>

#define MXN (520)

int n, m;

struct Edge {
    int v, w;
};
std::vector<Edge> edge[MXN];

unsigned long long node[MXN], f[MXN][MXN], ans[MXN][MXN], bcp;

int rk[MXN];
bool cmp(int x, int y) { return node[x] < node[y]; }

signed main() {
#ifndef ONLINE_JUDGE
    freopen("B.in", "r", stdin);
#endif

    memset(f, -1, sizeof(f));
    memset(ans, -1, sizeof(ans));
    bcp = f[0][0];

    scanf("%d%d", &n, &m);

    for (int i = 1; i <= n; ++i)
        scanf("%lld", &node[i]);
    for (int i = 0, u, v, w; i < m; ++i)
        scanf("%d%d%d", &u, &v, &w), f[u][v] = f[v][u] = w;

    for (int i = 1; i <= n; ++i)
        rk[i] = i;
    std::sort(rk + 1, rk + 1 + n, cmp);

    for (int i = 1, j; i <= n; ++i)
        for (j = 1; j <= n; ++j)
            ans[i][j] = f[i][j] * std::max(node[i], node[j]);

    for (int i = 1, j, k, x; i <= n; ++i)
        for (x = rk[i], j = 1; j <= n; ++j)
            for (k = 1; k <= n; ++k)
                if (std::max(f[j][x], f[x][k]) <= f[j][k])
                    f[j][k] = std::max(f[j][x], f[x][k]), ans[j][k] = std::min(ans[j][k], f[j][k] * std::max(node[x], std::max(node[j], node[k])));

    for (int i = 1; i <= n; ++i)
        ans[i][i] = 0;
    for (int i = 1, j, k; i <= n; ++i, putchar('\n'))
        for (j = 1; j <= n; ++j)
            printf("%lld ", (ans[i][j] == bcp) ? (-1) : (ans[i][j]));

    return 0;
}

在预处理部分可能需要再研究一下, 我是后来该题的时候加了unsigned, 预处理成-1才过的, 可能有一些奇怪的地方需要注意.

C 传送爸爸

传送我 这题没写, 是BFS/SPFA水题

评论

0

还没有评论。