AtCoder Beginner Contest 050

A
输入流是 \(a + b\) 或者 \(a - b\) 。接受输入流然后输出结果。

    int a, b; char c; std::cin >> a >> c >> b;
    int ans = a + b;
    if (c == '+') std::cout << ans << "\n";
    else std::cout << ans - 2 * b << "\n";

B
题意:

一场比赛有 \(N\) 个问题,你解决第 \(i\) 个问题需要 \(T_i\) 秒。

\(M\) 杯饮料,它可以刺激你的大脑。第 \(i\) 杯饮料可以让第 \(P_i\) 个问题的解决时间变成 \(X_i\) 秒。且不会对其他问题造成影响。

假设你解决所有问题的时间是解决每个问题的时间的和。

回答 \(M\) 个独立询问,询问你喝且仅喝了第 \(i\) 杯饮料后,你需要多少时间解决所有问题。

\(1 \leq N, M \leq 100, 1 \leq T_i, X_i \leq 10^{5}, 1 \leq P_i \leq N\)

题解:

怎么说呢…… 维护一开始的 \(sum = \sum_{i = 1}^{N} T_i\)

然后第 \(i(1 \leq i \leq M)\) 个询问的答案是 \(sum - T_{p_i} + X_i\)

时间复杂度是显然的 \(O(N + M)\)

    int N; std::cin >> N;
    std::vector<int> T(N + 1);
    ll sum = 0;
    for (int i = 1; i <= N; i++) {
        std::cin >> T[i];
        sum += T[i];
    }
    int M; std::cin >> M;
    for (int i = 1; i <= M; i++) {
        int P, X; std::cin >> P >> X;
        std::cout << sum - T[P] + X << "\n";
    }

C
题意:

\(n\) 个人昨天排成一行,但是他们今天忘了他们昨天站在哪里。当然,每个人都记得一个事实:他记得左边的人数减去右边的人数的绝对值。第 \(i\) 个人的这个数值是 \(A_i\)

询问昨天共有多少种可能的排列,答案 \(\bmod 10^{9} + 7\)

可能存在不正确的信息,导致不存在答案,输出 \(0\)

\(1 \leq N \leq 10^{5}, 0 \leq A_i \leq N - 1\)

题解:

设第 \(i\) 个人昨天的位置为 \(P_i\)
设昨天第 \(i\) 个人左边有 \(CL_i\) 个人,右边有 \(CR_i\) 个人,于是有:

\[\begin{cases} CL_i + CR_i = n - 1 \\ |CL_i - CR_i| = A_i \\ \end{cases} \Rightarrow \begin{aligned} CL_i &= \frac{n - 1 + A_i}{2}, CR_i = \frac{n - 1 - A_i}{2} \\ or \\ CL_i &= \frac{n - 1 - A_i}{2}, CR_i = \frac{n - 1 + A_i}{2} \\ \end{aligned} \Rightarrow \begin{aligned} P_{i_1} &= n - \frac{n - 1 + A_i}{2} \\ or \\ P_{i_2} &= n - \frac{n - 1 - A_i}{2} \\ \end{aligned} \]

如果下标没有越界,对 \(i\) 可能出现的位置记录一次贡献。这需要讨论是否 P1 、 P2 相同。

\(CL < 0\)\(CR > N\)\(2 \nmid n - 1 + A_i\)
\(\forall i \in [1, N], v_i \neq 2 \ s.t.\ 2 \mid N\) ,或 $\forall i \in [1, N] \sum [v_i = 2] = N - 2, \sum [b_i = 1] = 1 \ s.t.\ 2 \nmid N $ 。则信息有误。

否则可以分成 \(M = \lfloor \frac{N}{2} \rfloor 2\) 组,每组两个人,可能的排列方案是 \(2\) 。由乘法原理答案为 \(2^{M}\) 。若 \(2 \nmid N\) ,多出来的单人组的乘法贡献是 \(1\)

时间复杂度 \(O(N + \log N)\)

    int N; std::cin >> N;
    std::vector<int> A(N + 1), V(N + 1);
    for (int i = 1; i <= N; i++) {
        std::cin >> A[i];
    }
    int ok = 1;
    for (int i = 1; i <= N; i++) {
        int P1 = N - (N - 1 + A[i]) / 2, P2 = N - (N - 1 - A[i]) / 2;
        if (P1 > N || P2 < 0 || (N - 1 + A[i]) % 2 == 1) { ok = 0; break; }
        V[P1]++, V[P2]++;
        if (P1 == P2) V[P1]--;
    }
    if (N % 2 == 0) for (int i = 1; i <= N; i++) ok &= V[i] == 2;
    if (N % 2 == 1) {
        int f1 = 0, f2 = 0;
        for (int i = 1; i <= N; i++) f1 += (V[i] == 1), f2 += (V[i] == 2);
        ok &= (f1 == 1 && f2 == N / 2 * 2);
    }
    if (!ok) std::cout << 0 << "\n";
    else {
        int ans = 1, M = N / 2;
        while (M--) ans = (ans << 1) % MOD;
        std::cout << ans << "\n";
    }

D
题意:

给定一个正整数 \(N\) 。找到满足下述条件的 \(u, v(0 \leq u,v \leq N)\) 的对数。

\(\forall (u, v)\)\(\exists a, b(0 \leq a, b)\) 满足

\[\begin{cases} a \oplus b = u \\ a + b = v \\ \end{cases} \]

结果 \(\mod 10^{9} + 7\) 输出。

\(1 \leq N \leq 10^{18}\)

题解:

由异或是二进制下不进位的加法,不难有 \(u \leq v\)

\((u, v)\) 的计数,可以枚举 \(v\) ,然后计算 \(\leq v\) 的所有 \(u\) ,转化为 DP 。

等价于枚举 \(a + b\) ,计算 \(|\{a \subset b\}|\)

经典的数位 DP :\(f_{i, j}\) 考虑了 \(i\) 位,\(a + b = j\) 时的答案。

转移为:

\[f_{i, j} = f_{i - 1, (j << 1) + 0} + f_{i - 1, (j << 1) + 2} + f_{i - 1, (j << 1) + 2} \]

进位的三种结果对应 \((a << 1) + 0, (b << 1) + 0\)\((a << 1) + 0, (b << 1) + 1\)\((a << 1) + 1, (b << 1) + 1\)

不难滚动优化:

\[f_{j} += f_{(j << 1) + 0} + f_{(j << 1) + 2} + f_{(j << 1) + 2} \]

可以离散化或者用 map DP 。

const int MOD = 1E9 + 7;
template <class T,const int P = 2119969 /*314159,451411,1141109,2119969*/ >
struct hashmap {
    u64 id[P];
    T val[P];
    int rec[P]; // del: no many clears
    hashmap() { memset(id, -1, sizeof id); }

    T get(const u64 &x) const {
        for (int i = int(x % P), j = 1; ~id[i]; i = (i + j) % P, j = (j + 2) % P) {
            if (id[i] == x)
                return val[i];
        }
        return 0;
    }

    T& operator [] (const u64 &x) {
        for (int i = int(x % P), j = 1; ; i = (i + j) % P, j = (j + 2) % P) {
            if (id[i] == x) return val[i];
            else if (id[i] == -1llu) {
                id[i] = x;
                rec[++rec[0]] = i; // del: no many clears
                return val[i];
            }
        }
    }

    void clear() { // del
        while(rec[0])
            id[rec[rec[0]]] = -1, val[rec[rec[0]]] = 0, --rec[0];
    }

    void fullclear() {memset(id, -1, sizeof id); rec[0] = 0; }
};
hashmap<u64> f;
void solve() {
    u64 N; std::cin >> N;
    f.clear();
    f[0] = 1;
    std::function<void(u64)> dfs = [&](u64 x) {
        if (f.get(x) != 0) return;
        if (x >= 0) dfs(x-0 >> 1), f[x] = (f[x] + f[x-0 >> 1]) % MOD;
        if (x >= 1) dfs(x-1 >> 1), f[x] = (f[x] + f[x-1 >> 1]) % MOD;
        if (x >= 2) dfs(x-2 >> 1), f[x] = (f[x] + f[x-2 >> 1]) % MOD;
    };
    dfs(N);
    std::cout << f[N] << "\n";
}
posted @ 2023-03-15 16:05  03Goose  阅读(22)  评论(0)    收藏  举报