Contest7986 - 综合训练-113

A 数字魔术

HDU4952 Number Transformation

Tag:人类智慧

个人评价:绿

切了。

思路

强行写开,注意到它是一个这样的结构:

\[\left\lceil \left\lceil \left\lceil n \times \frac 1 2 \right\rceil \times \frac 2 3 \right\rceil \times \frac 3 4 \right\rceil \times \cdots \]

\(n\) 一直在变小,而乘的数趋近于 \(1\),猜想:到某一个数之后,取整之后的值不变。

然后就做完了。

证明这个方法的时间复杂度是 \(O(\sqrt n)\)

\[\begin{aligned} n' &\ge \frac {i \times n} {i+1} \\ n' &\ge n - \left\lceil \frac n {i+1} \right\rceil \end{aligned}\]

如果 \(i+1 < n\),则 \(n\) 不变。

注意到到 \(i+1\) 这一步时,\(n\) 大约是原先的 \(n\)\(\frac 1 i\)\(\frac n i < i+1\)\(i = O(\sqrt n)\)

代码

        cin >> n >> k;
        if (n == 0 && k == 0) break; // 多测

        rep(i, 2, k) {
            ll t = ceil_div(n * (i-1), i);
            if (t < n)
                n = t;
            else
                break;
        }
        n *= k;
        cout << "Case #" << Case << ": " << n << '\n';

B

HDU4947 GCD Array

Tag:莫比乌斯反演,Dirichlet

个人评价:紫

思路

\(d \nmid n\) 直接扔掉。

\(\gcd\) 柿子直接莫。

这个贡献在 Dirichlet 前缀差分上容易实现。同时,从 Dirichlet 前缀差分上求原函数的前缀和只有一个根号的代价

\(O(n \sqrt n \log n)\) 做法

\[\begin{aligned} & v \times [\gcd(i, n) = d] \\ =& v \times [\gcd(\frac i d, \frac n d) = 1]\\ =& v \times \sum\limits_{k \mid \frac i d \land k \mid \frac n d} \mu(k) \\ \end{aligned}\]

\[A_i = \sum\limits_{j \mid i} C_j \]

\(A\)\(C\) 的 Dirichlet 前缀和,\(C\)\(A\) 的 Dirichlet 前缀差分。

查询

\[\sum\limits_{i=1}^x A_i = \sum\limits_{i=1}^x \sum\limits_{j \mid i} C_j = \sum\limits_{j=1}^x \left\lfloor \frac x j \right\rfloor C_j \]

数论分块计算。需要维护 \(C\) 的前缀和。

时间复杂度 \(O(\sqrt n \log n)\)

修改

枚举 \(\frac n d\) 的约数 \(k\),给 \(C_{k \times d}\) 加上 \(v \times \mu(k)\)

时间复杂度 \(O(\sqrt n \log n)\)(精细实现是 \(O(d(n) \log n)\))。

\(C\) 有单点修改 & 前缀和查询,使用树状数组维护。

时间复杂度 \(O(n \sqrt n \log n)\)

Fenwick C;
void modify(int k, int d, ll v) {
    C.add(k * d, v * mu[k]);
}
void op1(int n, int d, ll v) { // n 此时已经变成 n / d
    for (int k = 1; k * k <= n; k++) if (n % k == 0) {
        modify(k, d, v);
        if (k * k != n)
            modify(n / k, d, v);
    }
}
ll op2(int x) {
    ll ans = 0;
    for (int l = 1, r; l <= x; l = r+1) {
        int val = x / l;
        r = x / val;
        ans += val * (C.query(r) - C.query(l-1));
    }
    return ans;
}

优化:\(O(n \sqrt {n \log n})\) 做法

瓶颈在查询,考虑怎么的根号平衡一下。

在数论分块那一步进行根号分治。

  • \(j < B\) 暴力。复杂度 \(\Theta(B)\)
  • \(j \ge B\) 时,\(\lfloor \frac x j \rfloor\) 至多有 \(\Theta(\frac x B)\) 段。沿用老方法,复杂度 \(\Theta(\frac {x \log x} B)\)

\(B = \Theta(\sqrt {x \log x})\) 平衡。

C

HDU4955 Tree

D

P7735 [NOI2021] 轻重边 很像。

posted @ 2024-12-07 15:59  August_Light  阅读(33)  评论(0)    收藏  举报