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 掉的不要来线下单杀我)。
本文来自博客园,作者:HS_fu3,转载请注明原文链接:https://www.cnblogs.com/HS-fu3/p/19046828

浙公网安备 33010602011771号