1 条题解

  • 1
    @ 2022-7-27 13:56:11

    说句闲话: 出题人这题做了半年。

    Part 0

    显然,无解是不可能的,因为 nn121^2 的和就是 nn,而 m1m \ge 1,因此这一定是合法的方案。

    Part 1

    设答案为 kk,求证:pkp+4p \le k \le p+4,其中 p=nm2p=\lfloor\dfrac{n}{m^2}\rfloor

    证明:

    • 先证明 kpk \ge p

      k<pk<p,则 km2<pm2k \cdot m^2 < p \cdot m^2

      显然 pnm2p \le \dfrac{n}{m^2},因此 pm2np \cdot m^2 \le n

      于是,km2<pm2nk \cdot m^2 < p \cdot m^2 \le n,即 km2<nk \cdot m^2 < n

      由于每个完全平方数都不大于 m2m^2,因此 kk 个完全平方数的和最大只能是 km2k \cdot m^2

      然而,km2<nk \cdot m^2 < n,因此,kk 个完全平方数的和绝不可能等于 nn,矛盾。

      综上,k<pk<p 的假设不成立,因此 kpk \ge p得证。

    • 再证明 kp+4k \le p+4

      n=pm2+qn=p \cdot m^2 +q

      显然 pnm2<p+1p \le \dfrac{n}{m^2}<p+1,因此 pm2n<(p+1)m2p \cdot m^2 \le n<(p+1) \cdot m^2,于是 0q<m20 \le q <m^2

      根据这个定理,总有四个非负整数 e1,e2,e3,e4e_1,e_2,e_3,e_4,使得 q=(e1)2+(e2)2+(e3)2+(e4)2q=(e_1)^2+(e_2)^2+(e_3)^2+(e_4)^2

      由于 q<m2q <m^2,而 (e1)2,(e2)2,(e3)2,(e4)2(e_1)^2,(e_2)^2,(e_3)^2,(e_4)^2 均非负,因此 (e1)2,(e2)2,(e3)2,(e4)2(e_1)^2,(e_2)^2,(e_3)^2,(e_4)^2 均不大于 m2m^2,满足「不大于 m2m^2」的要求。

      qq 代入,得 n=pm2+(e1)2+(e2)2+(e3)2+(e4)2n=p \cdot m^2 +(e_1)^2+(e_2)^2+(e_3)^2+(e_4)^2

      此时,等式右边共 (p+4)(p+4) 个完全平方数,故 kp+4k \le p+4(为 00 的项可以删去,因此可能少于 (p+4)(p+4) 个),得证。

    综上所述,pkp+4p \le k \le p+4原命题得证。

    显然,由于 pkp+4p \le k \le p+4kk 的取值只有 55 种(ppp+1p+1p+2p+2p+3p+3p+4p+4)。因此,考虑暴力枚举 kk 的值,每次判断是否可行(若 km2<nk \cdot m^2 < n直接跳过,保证 km2nk \cdot m^2 \ge n)。

    Part 2

    先来考虑一种错误的解法40 pts40\ \text{pts}):按照与加强前的原题O(nn)O(n\sqrt{n}) 解法类似的思路,使用完全背包求解,时间复杂度 O(nm2+Q)O(nm^2+Q),超时。

    显然,使得上述算法超时的主要原因是状态太多(对应 O(nm2+Q)O(nm^2+Q) 中的 nn)。要想优化此算法,必须减少状态数。

    由于正向求解遇到了困难,考虑反向求解:每次枚举 kk 的值时,先假设所有的完全平方数都是 m2m^2,再把一部分 m2m^2 修改为其它小于 m2m^2 的完全平方数,使总和减小(倒扣),反向求解。

    于是,完全背包的定义发生了转变。

    Part 3

    定义 wi,jw_{i,j} 为:当 m=im=i 时,恰好倒扣 jj 至少需要修改的 m2m^2 的个数,若无法恰好倒扣 jj 则其值为 ++\infty。(1i100,j01 \le i \le 100,j \ge 0

    初始状态:

    • wi,0=0,wi,j=+.w_{i,0}=0,w_{i,j}=+\infty.
    • j0.j \neq 0.
    • (解释:前者无需倒扣,后者假定无法恰好倒扣,等待更新。)

    状态转移方程(顺序:按 jj 升序):

    • wi,j=min(wi,j,wi,j(i2x2)+1).w_{i,j} = \min(w_{i,j},w_{i,j-(i^2-x^2)}+1).
    • 其中 x=1,2,,i1x=1,2,\ldots,i-1,保证 j(i2x2)0.j-(i^2-x^2) \ge 0.
    • (解释:修改 11i2i^2(改为 x2x^2),倒扣 i2x2i^2-x^2。)

    由于需要从 km2k \cdot m^2 倒扣至 nn,共倒扣了 km2nk \cdot m^2 - n,因此 wm,km2nw_{m,k \cdot m^2 - n} 即为所需的答案。

    注意:若 wm,km2n>kw_{m,k \cdot m^2 - n} > k,则表明没有足够的 m2m^2 用于倒扣时的修改(或根本不可能恰好倒扣,此时 wm,km2n=+w_{m,k \cdot m^2 -n} = +\infty),该 kk 的值必须舍去。

    Part 4

    求证:倒扣的总量(km2nk \cdot m^2 - n即当 i=mi=m 时下标 jj 的上界)不大于 4m214 \cdot m^2-1

    证明:

    前面已经证明 pm2np \cdot m^2 \le n

    • pm2<np \cdot m^2 < n 时:

      此时有 pm2n1p \cdot m^2 \le n-1,因此 pm2+4m2n+4m21p \cdot m^2 +4 \cdot m^2 \le n+4 \cdot m^2-1,即 (p+4)m2n+4m21(p+4) \cdot m^2 \le n+4 \cdot m^2-1

      又因为前面已经证明 kp+4k \le p+4,因此 km2(p+4)m2k \cdot m^2 \le (p+4) \cdot m^2

      于是 $k \cdot m^2 \le (p+4) \cdot m^2 \le n+4 \cdot m^2-1$,即 km2n+4m21k \cdot m^2 \le n+4 \cdot m^2-1

      由此可得 km2n4m21k \cdot m^2-n \le 4 \cdot m^2-1

    • pm2=np \cdot m^2 = n 时:

      显然此时 n=pm2n = p \cdot m^2。该等式右边共 pp 个完全平方数,故 k=pk =p(前面已经证明 kpk \ge p)。

      将上面两个等式代入计算,得 km2n=0k \cdot m^2 - n =0。显然 4m21>04 \cdot m^2-1>0

    综上所述,km2n+4m21k \cdot m^2 \le n+4 \cdot m^2-1原命题得证。

    wi,j+w_{i,j} \neq +\infty,求证:wi,j26w_{i,j} \le 26

    证明:

    根据上文,模拟可得,过程略去。原命题得证。

    Part 5

    最终,时间复杂度 O(m4+Q)O(m^4+Q),空间复杂度 O(m3)O(m^3),可以通过此题。

    Part 6

    std:

    #include <bits/stdc++.h>
    using namespace std;
    const int M = 100 + 5;
    vector <char> w[M];
    int main() {
        for (int i = 1; i <= 100; i ++) {
            w[i].resize(4 * i * i + 5);
            w[i][0] = 0;
            for (int j = 1; j <= 4 * i * i - 1; j ++) {
                w[i][j] = 27;
                for (int x = i - 1; x >= 1; x --)
                    if (j - (i * i - x * x) >= 0) w[i][j] = min(w[i][j], (char) (w[i][j - (i * i - x * x)] + 1));
            }
        }
        int Q;
        scanf("%d", &Q);
        while (Q --) {
            long long n;
            int m;
            scanf("%lld %d", &n, &m);
            long long k = n / (m * m);
            while (k * m * m < n || w[m][k * m * m - n] == 27 || w[m][k * m * m - n] > k) k ++;
            printf("%lld\n", k);
        }
        return 0;
    }
    
    • 1

    信息

    ID
    3
    时间
    1750ms
    内存
    128MiB
    难度
    7
    标签
    (无)
    递交数
    15
    已通过
    5
    上传者