Expression 题解

正文

一道值得铭记的题(绝对不是因为我调了一上午)。

更好的阅读体验

一句话题意:a+b problem(加强版)

好吧其实是搜索。

只要不停的搜,不停的搜,不停的搜就完了。

如何搜索?

用数位 dp 思路,依次判断每一位填什么,从低位向高位填数。

dfs 中传 8 个参

inline void dfs(int a, int b, int c, int a1, int a2, int a3, int dep, int up)

分别为:原a,原b,原c,当前a,当前b,当前c,正在填第几位,是否进位。

虽然是数位 dp 思路搜索,但并不是依次枚举(否则等着爆炸吧)。

实际的情况只有 4 种,分别为:填入a,b,c的最低位;填入a,b的最低位;填入a,c的最低位;填入b,c的最低位。

所以时间复杂度可以保证,为\(O(4^{12} ~4^{13})\)(取决于你钦定的位数最大值,反正能过就对了)。

到这里基本就可以结束了\(\cdots\)

But,如果你不注意进位,就可以愉快的调一上午了(嘻嘻嘻嘻嘻嘻)

关于进位的部分还是自己推一下的好(绝对不是因为我懒得写)。

再就是统计答案,注意,这里搜到的答案不一定为最优,且不能通过最大位数判断是否更优(由于是暴搜)。

此时就需要朴素的方法更新答案。

inline int len(int x) { int ans = 0; while (x) ans++, x /= 10; return ans; }

算出每个数十进制下位数,然后直接加,判断是否更优。

挺暴力的。

然后就可以愉快的 A 了。

点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int inf = 1e18;
int a, b, c, ans1, ans2, ans3,laslen = inf;
int f[20];
string s;

inline int len(int x)
{
    int ans = 0;
    while (x)
        ans++, x /= 10;
    return ans;
}

inline void dfs(int a, int b, int c, int a1, int a2, int a3, int dep, int up)
{
    if (dep > 12)
        return;
    if (!a && !b && !c && !up && a1 + a2 == a3)
    {
        int now = len(a1) + len(a2) + len(a3);
        if (laslen > now)
        {
            ans1 = a1, ans2 = a2, ans3 = a3;
            laslen = now;
        }
        return;
    }
    int now1 = a % 10, now2 = b % 10, now3 = c % 10;
    if (up + now1 + now2 == now3)//a,b,c
        dfs(a / 10, b / 10, c / 10, a1 + now1 * f[dep], a2 + now2 * f[dep], a3 + now3 * f[dep], dep + 1, 0);
    else if(up + now1 + now2 - 10 == now3)
        dfs(a / 10, b / 10, c / 10, a1 + now1 * f[dep], a2 + now2 * f[dep], a3 + now3 * f[dep], dep + 1, 1);

    if (now2 + up > now3)//b,c
        dfs(a, b / 10, c / 10, a1 + (10 + now3 - now2 - up) * f[dep], a2 + now2 * f[dep], a3 + now3 * f[dep], dep + 1, 1);
    else
        dfs(a, b / 10, c / 10, a1 + (now3 - now2 - up) * f[dep], a2 + now2 * f[dep], a3 + now3 * f[dep], dep + 1, 0);

    if (now1 + up > now3)//a,c
        dfs(a / 10, b, c / 10, a1 + now1 * f[dep], a2 + (10 + now3 - now1 - up) * f[dep], a3 + now3 * f[dep], dep + 1, 1);
    else
        dfs(a / 10, b, c / 10, a1 + now1 * f[dep], a2 + (now3 - now1 - up) * f[dep], a3 + now3 * f[dep], dep + 1, 0);

    if (now1 + now2 + up > 9)//a,b
        dfs(a / 10, b / 10, c, a1 + now1 * f[dep], a2 + now2 * f[dep], a3 + (up + now1 + now2 - 10) * f[dep], dep + 1, 1);
    else
        dfs(a / 10, b / 10, c, a1 + now1 * f[dep], a2 + now2 * f[dep], a3 + (up + now1 + now2) * f[dep], dep + 1, 0);
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> s;//读入也可用scanf
    int now = 0;
    f[1] = 1;
    for (int i = 2; i < 18; i++)
        f[i] = f[i - 1] * 10;
    while (s[now] >= '0' && s[now] <= '9')
    {
        a = a * 10 + s[now] - '0';
        ++now;
    }
    now++;
    while (s[now] >= '0' && s[now] <= '9')
    {
        b = b * 10 + s[now] - '0';
        ++now;
    }
    now++;
    while (s[now] >= '0' && s[now] <= '9' && now < s.size())
    {
        c = c * 10 + s[now] - '0';
        ++now;
    }
    dfs(a, b, c, 0, 0, 0, 1, 0);
    cout << ans1 << "+" << ans2 << "=" << ans3;
    return 0;
}

闲话

其实本来根本没有打算写题解,但这它值得铭记

首先不是因为调了一上午(这不是受辱时刻吗我记什么,我又没有奇怪癖好)。

原因是我在调我的错误代码时将洛谷上的 3 篇题解 hack 掉了(以防你不知道:洛谷上就 4 篇题解,幸存的一篇是 dp 做的,9 层循环,成功保证正确性 rank 1 和最劣解 rank 1)。

然后发现机房里其他人的解法好像和第一篇题解类似\(\cdots\)

所以 hack 了机房内部 12 份代码(有 1 份是 spj 写错了导致没被叉掉,另一份在 spj 假的情况下过了但不确定代码正确性)。

自此,已至巅峰(一上午没白调哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈)。

(所以被 hack 掉的不要来线下单杀我)。

posted @ 2025-08-19 16:00  HS_fu3  阅读(28)  评论(1)    收藏  举报