AtCoder Beginner Contest 362 补题记录(A~E,G)

A

分三类情况讨论即可。

void solveqwq() {
    int r = io.read(), g = io.read(), b = io.read();
    string qwq = io.readstring();
    if (qwq == "Blue") printf("%lld\n", min(r, g));
    else if (qwq == "Red") printf("%lld\n", min(g, b));
    else printf("%lld\n", min(r, b));
}

B

求出三角形三条边然后暴力判断即可。

void solveqwq() {
    int xa = io.read(), ya = io.read(), xb = io.read(), yb = io.read(), xc = io.read(), yc = io.read();
    int AB = (xa - xb) * (xa - xb) + (ya - yb) * (ya - yb);
    int AC = (xa - xc) * (xa - xc) + (ya - yc) * (ya - yc);
    int BC = (xb - xc) * (xb - xc) + (yb - yc) * (yb - yc);
    int a[3] = {AB, AC, BC}; sort(a, a + 3);
    if (a[0] + a[1] == a[2]) puts("Yes");
    else puts("No");
}

C

唯一一道不是原题且有意义的题

首先这个构造可以构造出来的和一定在范围 \([L,R]\) 中。然后考虑开两个前缀和分别记录左端点和右端点的和。

此时枚举每一个区间,分两种情况讨论:

  • 此时取 \(L_i\) 的值仍然可行。则继续贪心取 \(L_i\)。这个(可行)可以通过刚刚预处理出的前缀和来计算。
  • 此时取 \(L_i\) 的值仍然不可行。直接套公式计算出最小可行的值,然后剩下的值全部选取 \(R_i\) 即可。

时间复杂度为 \(O(n)\)

void solveqwq() {
    int n = io.read();
    for (int i = 1; i <= n; ++i) l[i] = io.read(), r[i] = io.read();
    int minv = 0, maxv = 0;
    for (int i = 1; i <= n; ++i) minv += l[i], maxv += r[i];
    if (minv > 0 || maxv < 0) puts("No");
    else {
        puts("Yes");
        for (int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + r[i], qwq[i] = qwq[i - 1] + l[i];
        vector<int> res;
        for (int i = 1; i <= n; ++i) {
            int tmp = qwq[i - 1] + sum[n] - sum[i] + l[i];
            if (tmp >= 0) res.emplace_back(l[i]);
            else {
                res.emplace_back(l[i] - tmp);
                for (int j = i + 1; j <= n; ++j) res.emplace_back(r[j]);
                break;
            }
        }
        for (auto &val : res) printf("%lld ", val);
        puts("");
    }
}

D

《模板:单源最短路径》

代码不贴了。

E

\(f_{i,j,k}\) 为当前选取的最后一个元素为 \(i\),选取了 \(j\) 个元素,等差数列的公差为 \(k\) 的方案数。

则可以枚举 \(i\)\(j\)\(k\) 和上一个选择的元素 \(p\),然后有转移方程 \(f_{i,j,k}\leftarrow f_{p,j-1,k}\)

for (int i = 3; i <= n; ++i)
	for (int j = 3; j <= i; ++j)
		for (int k = 1; k <= idx; ++k)
			for (int p = j - 1; p < i; ++p)
				if (chg[k] == a[p] - a[i])
					f[i][j][k] = (f[i][j][k] + f[p][j - 1][k]) % mod;

但是时间复杂度为 \(O(n^5)\),会超时。

因此考虑优化。因为没人想要优化状态所以考虑优化枚举上一个选择元素 \(p\) 的过程。容易发现一个合法的 \(p\) 关于三元组 \((i,j,k)\) 而言,需要满足 \(k=a_i-a_p\)。因此考虑直接给所有符合这样元素的条件存储下来。具体的说:

\(g_{j,k,p}\) 表示选取 \(j\) 个元素,目前公差为 \(k\),且上一个元素值为 \(p\) 的方案数。

于是可以在枚举 \(f\) 的转移的时候一并转移上 \(g\)。此时 \(g\) 的转移为:\(g_{j,k,a_i}\leftarrow f_{i,j,k}\)

因此 \(f\) 的转移也可以通过 \(g\) 来优化,即为:\(f_{i,j,k}\leftarrow g_{j-1,k,a_i+k}\)

然后此时你需要在转移的过程中插入 \(j=2\) 的初始条件。因为 \(j\le 2\) 的时候任意一个 \(j\) 元组都符合条件,所以说 \(j=1\) 时答案为 \(n\)\(j=2\) 时答案为 \(\binom{n}{2}\)

然后因为 \(a_i\le 10^9\) 所以你还需要对所有的元素离散化。但是因为目前时间复杂度为 \(O(n^4)\) 再多一只 \(\log\) 都是致命打击所以说你可能需要一些【】来离散化,然后这样以来 dp 的方程变成了依托【】,代码就十分混乱。

还有就是【】在写这个题的时候忘记修改输入文件为 E 题样例,然后用 D 题样例虚空调试 1h。警钟砸碎。

void solveqwq() {
    // freopen(".out", "w", stdout);
    int n = io.read();
    for (int i = 1; i <= n; ++i) a[i] = io.read();
    if (n <= 2) {
        if (n == 1) printf("%lld\n", n);
        else printf("%lld %lld\n", n, n * (n - 1) / 2);
    } else {
        vector<int> vec;
        for (int i = 1; i <= n; ++i)
            for (int j = i + 1; j <= n; ++j)
                vec.emplace_back(a[i] - a[j]);
        sort(vec.begin(), vec.end());
        vec.erase(unique(vec.begin(), vec.end()), vec.end());
        unordered_map<int, int> mp, __;
        int idx = 0;
        for (auto &val : vec) mp[val] = ++idx, tru[idx] = val;
        set<int> se;
        for (int i = 1; i <= n; ++i)
            se.insert(a[i]), b[i] = a[i];
        int idxx = 0;
        for (auto &val : se) __[val] = ++idxx, rid[idxx] = val;
        // f[i][j][k] 表示当前最后一个元素是 i 选取了 j 个元素 差为 k 的方案数
        // g[j][k][p] 表示选取 j 个元素差为 k 上一个元素值为 p 的方案数
        for (int i = 2; i <= n; ++i) {
            for (int j = i; j >= 3; j--) {
                for (int k = 1; k <= idx; ++k)
                    f[i][j][k] = (f[i][j][k] + g[j - 1][k][a[i] + tru[k]]) % mod;
                for (int k = 1; k <= idx; ++k)
                    g[j][k][a[i]] = (g[j][k][a[i]] + f[i][j][k]) % mod;
            }
            for (int j = 1; j < i; ++j)
                g[2][mp[a[j] - a[i]]][a[i]] = (g[2][mp[a[j] - a[i]]][a[i]] + 1) % mod;
        }
        // for (int i = 1; i <= n; ++i)
        //     for (int j = 1; j <= i; ++j)
        //         for (int k = 1; k <= idx; ++k)
        //             if (j <= 3)
        //                 printf("f[%lld][%lld][%lld] = %lld\n", i, j, tru[k], f[i][j][k]);
        printf("%lld %lld ", n, n * (n - 1) / 2);
        for (int i = 3; i <= n; ++i) {
            int s = 0;
            for (int j = i; j <= n; ++j)
                for (int k = 1; k <= idx; ++k)
                    s = (s + f[j][i][k]) % mod;
            printf("%lld ", s);
        }
        puts("");
    }
}

G

《模板:AC 自动机 III》

代码不贴了。

posted @ 2024-07-13 22:42  yhbqwq  阅读(37)  评论(0编辑  收藏  举报