1 条题解
-
0
自动搬运
来自洛谷,原作者为

rickyxrc
就这样。搬运于
2025-08-24 21:49:15,当前版本为作者最后更新于2023-07-18 09:54:39,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
本文章遵守知识共享协议 CC-BY-NC-SA,同步发表于洛谷题解区,转载时须在文章的任一位置附上原文链接和作者署名(rickyxrc)。推荐在我的个人博客阅读。
模拟赛 T1 是这个,然后喜提保龄,有感而发,写一篇题解。
十分感谢 itshawn 和 刘辰雨 对本题解的二次润色打磨,并修复了很多讲的不清楚和错误的细节。
题面大意
给定一个数 ,要求将 表示成一些 的数之和/差的形式,要求用的数最少,求方案数模 的结果。
解题思路
首先我们不难想到使用高精度,将 进行四进制拆分,拆成低位起的数组。
例如 ,我们的 数组就是 ,下文所讨论的状态转移均在此前提下进行。
然后我们考虑状态设计,我们定义第一维为已经规划到的位数,第二维为使用的数字总量,第三维为是否有数字进位到下一位。
注意:在我们的状态转移过程中,使用的数字凑出的总和始终不变,我们只是在进行等价变换。
那么我们就针对进位和不进位分别讨论。
如果这一位不进位,那么我们就直接将数放上去。
如果这一位有进位,那么我们需要考虑两种情况:
- 将值加上 个更大(是现在 倍)的数,为了保持这两位的数字总和不变,仍是原来的 ,将其减去 ,总花费为 个数。
- 将值加上 个更大(是现在 倍)的数,为了保持这两位的数字总和不变,仍是原来的 (因为上一位有进位),将其减去 ,总花费为 个数。
然后代码就不难写了,容易发现第一位可以滚掉节省空间(校内赛只给 32M),最后结果是第一个非零的 。
代码如下:
#include <stdio.h> #include <string.h> #include <ctype.h> #include <vector> #define maxn 3007 typedef long long i64; const i64 mod = 1000000000; int min(int a, int b); int max(int a, int b); struct Int { int li[maxn], len; Int(); void fix(); void read(); void write(); int &operator[](int x); }; Int operator+(Int a, Int b); Int operator*(Int a, i64 b); i64 pow(i64 x, i64 p); bool operator>(Int a, Int b); bool operator==(Int a, Int b); Int operator-(Int a, Int b); Int n, c, pow4[maxn]; i64 res = 0, mxval, cnt[maxn], now, dp[2][maxn][2]; int main() { n.read(); pow4[0][0] = 1, pow4[0].len = 1; for (mxval = 1; mxval < maxn; mxval++) { pow4[mxval] = pow4[mxval - 1] * 4; if (pow4[mxval] > n) break; } for (int j = mxval - 1; j >= 0; j--) { while (n > pow4[j]) cnt[j]++, n = n - pow4[j]; if (pow4[j] == n) { cnt[j]++; break; } } dp[now][0][0] = 1; for (int i = 0; i < mxval; i++) { now ^= 1; memset(dp[now], 0, sizeof dp[now]); for (int j = 0; j + cnt[i] < maxn; j++) { dp[now][j + cnt[i]][0] = (dp[now][j + cnt[i]][0] + dp[now ^ 1][j][0]) % mod; dp[now][j + cnt[i]][0] = (dp[now][j + cnt[i]][0] + dp[now ^ 1][j][1]) % mod; dp[now][j + 5 - cnt[i]][1] = (dp[now][j + 5 - cnt[i]][1] + dp[now ^ 1][j][0]) % mod; dp[now][j + 3 - cnt[i]][1] = (dp[now][j + 3 - cnt[i]][1] + dp[now ^ 1][j][1]) % mod; } } for (int i = 0; i < maxn; i++) if (dp[now][i][0] + dp[now][i][1]) { printf("%d", dp[now][i][0] + dp[now][i][1]); return 0; } return 0; }
- 1
信息
- ID
- 2541
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者