• AtCoder Regular Contest 116 (A~F补题记录)


    补题链接:Here

    第一次打 ARC,被数学题虐惨了

    赛后部分数学证明学习自 ACwisher

    A - Odd vs Even

    (T(1≤T≤2×10^5))组测试数据,每次询问一个正整数 (N(1≤N≤2×10^{18})) 的奇数因子多还是偶数因子多。


    【方案一】

    设n有cnt个质因子2,
    假设n有x个奇数因子,那么就会有m*(2^(cnt)-1)种偶数因子,即用cnt个2的子集和奇数因子配对.
    
    因此:
    当cnt=0时,没有偶数因子,此时奇数因子多.
    当cnt=1时,偶数因子和奇数因子一样多.
    当cnt>=2时,偶数因子比奇数因子多.
    
    using ll = long long;
    void solve() {
        ll cnt = 0, n; cin >> n;
        while (n % 2 == 0) n /= 2, cnt++;
        if (cnt == 0)cout << "Odd
    ";
        else if (cnt == 1)cout << "Same
    ";
        else if (cnt >= 2)cout << "Even
    ";
    }
    

    【方案二】

    赛后打了一下表,

    发现设 (N = 4k + r)

    • (r = 2) 时,(N = 4k + 2 = 2(2k +1))

      偶数因子有 (2)(2(2k + 1)) ,奇数因子有 (1)(2k + 1)

      (d|(2k + 1))(d) 不是 (1)(2k + 1),则 (d) 一定为奇数,且同时会贡献 (2d) 这一偶数因子

    • (r = 0) 时,(N = 4k)

      偶数因子个数至少是奇数因子的两倍

    • (r = 1 or 3)

      偶数因子个数为 0 个,奇数因子至少 2 个

    using ll = long long;
    void solve() {
        ll n; cin >> n;
        if (n % 4 == 0)cout << "Even
    ";
        else if (n % 2 == 0)cout << "Same
    ";
        else cout << "Odd
    ";
    }
    

    B - Products of Min-Max

    给出一个包含 (n) 个数的序列 (A),有 (2^{n−1})(A) 的非空子序列 (B)

    (sum max(B) imes min(B))


    先将序列按升序排序,

    [egin{split} ans &= sum_{i = 1}^{n}sum_{j = i + 1}^na_i imes a_j + sum_{i = 1}^na_i^2 \ &=sum_{i = 1}^na_i(sum_{j = i + 1}^na_j imes 2^{j - i + 1}) + sum_{i = 1}^na_i^2\ & 令 f(i) = sum_{j = i + 1}^na_j imes 2^{j - i + 1}\ &f(i - 1) = sum_{j = i + 1}^na_j imes 2^{j - i}\ & o f(i) = 2 imes f(i - 1) + a_i^2 end{split} ]

    • 时间复杂度:(mathcal{O}(n))
    using ll = long long;
    const int N = 2e5 + 10, mod =  998244353;
    ll a[N], n;
    void solve() {
        cin >> n;
        for (int i = 1; i <= n; ++i)cin >> a[i];
        sort(a + 1, a + 1 + n);
        ll ans = 0;
        for (int i = n, tmp = 0; i >= 1; --i) {
            ans = (ans + a[i] * a[i] % mod) % mod;
            ans  = (ans + a[i] * tmp % mod) % mod;
            tmp = (2ll * tmp + a[i]) % mod;
        }
        cout << ans << "
    ";
    }
    

    C - Multiple Sequences

    给定 (n(1le nle 2e5))(m(1le m le 2e5)) ,询问有多少满足长度为 (n) 的序列 (A)

    • (1le A_i le M(i = 1,2,...,N))
    • (A_{i + 1})(A_i) 的倍数 ((i = 1,2,...,N-1))

    注意到如果每次都有改变,顶多有 (19) 个数。调和级数一下是 (mathcal{O}(nlog n))

    先计算dp方案数。

    枚举有 (i) 个不同的数,对答案的贡献为 (C(n-1,i-1) imes sum_{j = 1}^m dp[i][j])

    注意第一个肯定是第一个,无需考虑

    using ll = long long;
    const int N = 2e5 + 10, mod = 998244353, K = 25;
    int n, m, f[K][N], fac[N], ifac[N];
    ll qpow(int x, int y ) {
        ll ans = 1;
        for (; y; y >>= 1, x = 1ll * x * x % mod)
            if (y & 1) ans = ans * x % mod;
        return ans;
    }
    int C(int x, int y) {
        return 1ll * fac[x] * ifac[y] % mod * ifac[x - y] % mod;
    }
    void solve() {
        cin >> n >> m;
        for (int i = 1; i <= m; i++) f[1][i] = 1;
        for (int i = 2; i <= 19; i++)
            for (int j = 1; j <= m; j++)
                for (int k = 2; 1ll * j * k <= m; k++)
                    f[i][j * k] = (f[i][j * k] + f[i - 1][j]) % mod;
        fac[0] = ifac[0] = 1;
        for (int i = 1; i <= n; ++i)fac[i] = 1ll * fac[i - 1] * i % mod;
        ifac[n] = qpow(fac[n], mod - 2);
        for (int i = n - 1; i >= 1; i--) ifac[i] = 1ll * ifac[i + 1] * (i + 1) % mod;
        // -------------------上方为初始化--------------------- //
        int ans = 0;
        for (int i = 1; i <= min(19, n); ++i) {
            int cnt = 0;
            for (int j = 1; j <= m; ++j)cnt = (cnt + f[i][j]) % mod;
            ans = (ans + 1ll * cnt * C(n - 1, i - 1) % mod) % mod;
        }
        cout << ans << '
    ';
    }
    

    D - I Wanna Win The Game

    给出 (n(1le n le5000))(m(1le m le5000)) ,询问有多少满足条件的长度为 (n) 的序列 (A)

    • (sum_iA_i = m)
    • (xor(A_i) = 0)
    • (A_i>=0)

    D题开始,没有做出来,参考了高 Rank 的解法

    显然每一位都有偶数个数选择。

    (f[i]) 表示 (n) 个数和为 (i) 的方案数

    (f[i] += C(n,2 imes j) imes f[(i -2 imes j)/2])

    是将之前和为((i−2×j)/2)(n) 个数左移一位,并选(2×j) 个数最后一位为 (1)

    using ll = long long;
    const int N = 5e3 + 10, mod = 998244353;
    ll fac[N], ifac[N], f[N];
    int n, m;
    ll qpow(int x, int y ) {
        ll ans = 1;
        for (; y; y >>= 1, x = 1ll * x * x % mod)
            if (y & 1) ans = ans * x % mod;
        return ans % mod;
    }
    ll C(int x, int y) {
        return 1ll * fac[x] * ifac[y] % mod * ifac[x - y] % mod;
    }
    void solve() {
        cin >> n >> m;
        fac[0] = ifac[0] = 1;
        for (int i = 1; i <= n; ++i)fac[i] = 1ll * fac[i - 1] * i % mod;
        ifac[n] = qpow(fac[n], mod - 2);
        for (int i = n -  1; i >= 1; i--)ifac[i] = 1ll * ifac[i + 1] * (i + 1) % mod;
        // ----------------------------------- //
        f[0] = 1;
        for (int i = 1; i <= m; ++i) {
            if (i & 1)continue;
            for (int j = 0; j <= m and i - 2 * j >= 0; ++j)
                f[i] = (f[i] + 1ll * C(n, 2 * j) * f[(i - 2 * j) / 2] % mod ) % mod;
        }
        cout << f[m];
    }
    

    E - Spread of Information

    (n(1≤n≤2e5)) 个点,选择 (k) 个为初始感染点,每秒沿边传播(扩张),求最快时间。


    二分最快时间(距离)

    (f_u u)子树内离他最近的感染点的距离
    (g_u u)子树内离他最远的非感染点的距离

    如果通过根节点中转能帮上 (g_u) 那么一定整个子树都已被覆盖

    其他情况,如果 (g_u=mid)(u) 必须成为初始感染点

    using ll = long long;
    const int N = 2e5 + 10, inf = 0x3f3f3f3f;
    vector<int>e[N];
    int n, k, mid, ret;
    int f[N], g[N];
    void dfs(int u, int fa) {
        g[u] = 0, f[u] = inf;
        for (int v : e[u]) {
            if (v == fa)continue;
            dfs(v, u);
            f[u] = min(f[u], f[v] + 1);
            g[u] = max(g[u], g[v] + 1);
        }
        if (f[u] + g[u] <= mid) g[u] = -inf;
        else if (g[u] == mid) f[u] = 0, g[u] = -inf, ret++;
    }
    bool check() {
        ret = 0;
        dfs(1, 0);
        if (g[1] >= 0)ret++;
        return ret <= k;
    }
    void solve() {
        cin >> n >> k;
        for (int i = 1, u, v; i < n; ++i) {
            cin >> u >> v;
            e[u].push_back(v);
            e[v].push_back(u);
        }
        int l = 0, r =  n, ans = n;
        while (l <= r) {
            mid = (r + l) >> 1;
            if (check())r = mid - 1, ans = mid;
            else l = mid + 1;
        }
        cout << ans;
    }
    

    F - Deque Game

    const int N = 2e5 + 10;
    int n, q[N];
    vector<int> a[N];
    int main() {
        scanf("%d", &n);
        int cnt = 0;
        for (int i = 1; i <= n; i++) {
            int k; scanf("%d", &k);
            for (int j = 0, x; j < k; j++)
                scanf("%d", &x), a[i].push_back(x);
            cnt += (k & 1 ^ 1);
        }
        ll sum = 0; int len = 0;
        for (int i = 1; i <= n; i++) {
            if (a[i].size() & 1 ^ 1) {
                if (a[i].size() == 2) {
                    sum += min(a[i][0], a[i][1]);
                    q[++len] = - (max(a[i][0], a[i][1]) - min(a[i][0], a[i][1]));
                } else {
                    int mid0 = a[i].size() / 2 - 1, mid1 = a[i].size() / 2 + 1 - 1, ret0, ret1;
                    if (cnt & 1 ^ 1) {
                        ret0 = min(a[i][mid0], max(a[i][mid0 - 1], a[i][mid0 + 1]));
                        ret1 = min(a[i][mid1], max(a[i][mid1 - 1], a[i][mid1 + 1]));
                    } else {
                        ret0 = max(a[i][mid0], min(a[i][mid0 - 1], a[i][mid0 + 1]));
                        ret1 = max(a[i][mid1], min(a[i][mid1 - 1], a[i][mid1 + 1]));
                    }
                    sum += min(ret0, ret1);
                    q[++len] = - (max(ret0, ret1) - min(ret0, ret1));
                }
            }
        }
        for (int i = 1; i <= n; i++) {
            if (a[i].size() & 1) {
                if (a[i].size() == 1) {
                    sum += a[i][0];
                } else {
                    int mid0 = (a[i].size() + 1) / 2 - 1;
                    if (cnt & 1 ^ 1)
                        sum += min(a[i][mid0], max(a[i][mid0 - 1], a[i][mid0 + 1]));
                    else
                        sum += max(a[i][mid0], min(a[i][mid0 - 1], a[i][mid0 + 1]));
                }
            }
        }
        sort(q + 1, q + len + 1);
        for (int i = 1; i <= len; i += 2) sum -= q[i];
        printf("%lld
    ", sum);
        return 0;
    }
    

    The desire of his soul is the prophecy of his fate
    你灵魂的欲望,是你命运的先知。

  • 相关阅读:
    【BZOJ】4349: 最小树形图
    【AtCoder】AtCoder Petrozavodsk Contest 001
    【LOJ】#2525. 「HAOI2018」字串覆盖
    趣味题:恺撒Caesar密码(c++实现)
    趣味问题:画图(c++实现)
    趣味问题:到底买不买
    成绩大排队
    A除以B问题
    2017-统计字符个数
    2016-数据的交换输出
  • 原文地址:https://www.cnblogs.com/RioTian/p/14823740.html
Copyright © 2020-2023  润新知