1 条题解

  • 0
    @ 2025-9-4 22:00:08

    说句闲话:

    • 出题人这题做了半年。
    • 当 m≤500m \le 500 时,贪心上界是 1385379313853793(n=13853793=57×4932n=13853793=57 \times 493^2,m=494m=494)。

    Part 0

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

    Part 1

    设答案为 kk,求证:p≤k≤p+4p \le k \le p+4,其中 p=⌊nm2⌋p=\lfloor\dfrac{n}{m^2}\rfloor。

    证明:

    • 先证明 k≥pk \ge p:

      若 k<pk<p,则 k⋅m2<p⋅m2k \cdot m^2 < p \cdot m^2。

      显然 p≤nm2p \le \dfrac{n}{m^2},因此 p⋅m2≤np \cdot m^2 \le n。

      于是,k⋅m2<p⋅m2≤nk \cdot m^2 < p \cdot m^2 \le n,即 k⋅m2<nk \cdot m^2 < n。

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

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

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

    • 再证明 k≤p+4k \le p+4:

      设 n=p⋅m2+qn=p \cdot m^2 +q。

      显然 p≤nm2<p+1p \le \dfrac{n}{m^2}<p+1,因此 p⋅m2≤n<(p+1)⋅m2p \cdot m^2 \le n<(p+1) \cdot m^2,于是 0≤q<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=p⋅m2+(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) 个完全平方数,故 k≤p+4k \le p+4(为 00 的项可以删去,因此可能少于 (p+4)(p+4) 个),得证。

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

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

    Part 2

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

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

    我们先来看一个例子:n=50025/m=10n=50025/m=10。显然,50025=500×102+5250025=500 \times 10^2+5^2,答案是 501501。

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

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

    Part 3

    定义 wjw_{j} 为:恰好倒扣 jj 至少需要修改的 m2m^2 的个数,若无法恰好倒扣 jj 则其值为 +∞+\infty。(1≤i≤100,j≥01 \le i \le 100,j \ge 0)

    初始状态:

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

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

    • wj=min⁡(wj,wj−(m2−x2)+1).w_{j} = \min(w_{j},w_{j-(m^2-x^2)}+1).
    • 其中 x=1,2,…,m−1x=1,2,\ldots,m-1,保证 j−(m2−x2)≥0.j-(m^2-x^2) \ge 0.
    • (解释:修改 11 个 m2m^2(改为 x2x^2),倒扣 m2−x2m^2-x^2。)

    由于需要从 k⋅m2k \cdot m^2 倒扣至 nn,共倒扣了 k⋅m2−nk \cdot m^2 - n,因此 wk⋅m2−nw_{k \cdot m^2 - n} 即为所需的答案。

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

    Part 4

    求证:倒扣的总量(k⋅m2−nk \cdot m^2 - n,即当 i=mi=m 时下标 jj 的上界)不大于 4⋅m2−14 \cdot m^2-1。

    证明:

    前面已经证明 p⋅m2≤np \cdot m^2 \le n。

    • 当 p⋅m2<np \cdot m^2 < n 时:

      此时有 p⋅m2≤n−1p \cdot m^2 \le n-1,因此 p⋅m2+4⋅m2≤n+4⋅m2−1p \cdot m^2 +4 \cdot m^2 \le n+4 \cdot m^2-1,即 (p+4)⋅m2≤n+4⋅m2−1(p+4) \cdot m^2 \le n+4 \cdot m^2-1。

      又因为前面已经证明 k≤p+4k \le p+4,因此 k⋅m2≤(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$,即 k⋅m2≤n+4⋅m2−1k \cdot m^2 \le n+4 \cdot m^2-1。

      由此可得 k⋅m2−n≤4⋅m2−1k \cdot m^2-n \le 4 \cdot m^2-1。

    • 当 p⋅m2=np \cdot m^2 = n 时:

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

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

    综上所述,k⋅m2≤n+4⋅m2−1k \cdot m^2 \le n+4 \cdot m^2-1,原命题得证。

    若 wj≠+∞w_{j} \neq +\infty,求证:wj≤57w_{j} \le 57。

    证明:

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

    Part 5

    最终,(每组数据)时间复杂度 O(m3+Q)O(m^3+Q),空间复杂度 O(m2)O(m^2),可以通过此题。

    Part 6

    std:

    #include <bits/stdc++.h>
    using namespace std;
    const int M = 500 + 12;
    const int K = 4 * M * M + 12;
    const int W = 58;
    char dp[K];
    signed main()
    {
       	int T;
       	scanf("%d", &T);
       	while (T--)
       	{
       		int m, Q;
       		scanf("%d %d", &m, &Q);
       		memset(dp, 0x7e, sizeof dp);
       		dp[0] = 0;
       		for (int u = 0; u <= 4 * m * m; u++)
       			for (int i = m - 1; i >= 1; i--)
       			{
       				int x = m * m - i * i;
       				if (u + x > 4 * m * m) break;
       				if (dp[u + x] > dp[u] + 1)  dp[u + x] = dp[u] + 1;
    			}
    		while (Q--)
    		{
    			long long n;
    			scanf("%lld", &n);
    			long long k = n / (m * m);
            	while (k * m * m < n || dp[k * m * m - n] >= W || dp[k * m * m - n] > k) k++;
            	printf("%lld\n", k);
    		}
    	}
        return 0;
    }
    
    • 1

    信息

    ID
    189
    时间
    1000ms
    内存
    128MiB
    难度
    8
    标签
    递交数
    2
    已通过
    1
    上传者