1. 题目来源
链接:3734. 求和
2. 题目解析
打表大法好。
每个数只能由 4 或 7 构成,最大不超过 1e9
,那么就是 10 位数,4 444 444 444
就是最大的了。每位有 2 种选法 4 / 7,那么总共就是
2
1
+
2
2
+
.
.
.
+
2
10
2^1+2^2+...+2^{10}
21+22+...+210 差不多 2000 多种选法。
所以可选方案很少,不管是打表还是 dfs
都很简单的可以搞出来。
[l, r]
区间中的各个数就能找到对应的
f
f
f 值,剩下的就转化成一个区间覆盖问题了。
y总板书:
最后将问题转化为区间求交集问题上很巧妙,且在求法上也非常巧妙。[l, r]
可能是个长区间,用一个个短区间 [q[i-1]+1, q[i]]
来慢慢将其覆盖,求区间交集,若有交集则本段
f
f
f 均为 q[i]
,若没交集,则区间长度为非正值,需要和 0 取 max
就判断出了,很是巧妙。
注意:
- 注意开
LL
。 - 区间覆盖动笔画一画…干想
WA
两次,动笔秒解决。
时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)
dfs预处理+区间求交集:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
LL l, r;
vector<LL> q;
// 很裸的 dfs,不太容易用二进制枚举写
// 有一个 0 在首位!
void dfs(int u, LL x) {
q.push_back(x);
if (u == 10) return ;
dfs(u + 1, x * 10 + 4);
dfs(u + 1, x * 10 + 7);
}
int main() {
dfs(0, 0);
sort(q.begin(), q.end());
cin >> l >> r;
LL res = 0;
// 求 [l, r] 区间与 [q[i-1]+1, q[i]] 区间的交集,交集部分,f 值均为 q[i]
// 没有交集时,应为 0
// 注意学习区间求交集的方法
for (int i = 1; i < q.size(); i ++ ) {
LL a = q[i - 1] + 1, b = q[i];
res += q[i] * max(0ll, (min(r, b) - max(l, a) + 1));
}
cout << res << endl;
return 0;
}
直接打表,找规律,新数位在旧数位的基础上扩增两倍。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
LL l, r;
vector<LL> a[10];
vector<LL> q;
/*
[l, r]
4, 7,
44, 47, 74, 77,
444, 447, 474, 477, 744, 747, 774, 777
[l, r] = [1, 9] = 4 * 4 + 7 * 3 + 44 * 2 = 125
*/
int main() {
cin >> l >> r;
a[0].push_back(4), a[0].push_back(7);
for (int i = 1; i < 10; i ++ ) {
for (int j = 0; j < a[i - 1].size(); j ++ ) {
// 最高位在上一位基础上扩增两倍
string s = to_string(a[i - 1][j]);
a[i].push_back(stoll('4' + s));
a[i].push_back(stoll('7' + s));
}
}
for (auto e : a)
for (auto c : e)
q.push_back(c);
sort(q.begin(), q.end());
// 处理区间覆盖,动笔画!!!
LL res = 0;
int le = lower_bound(q.begin(), q.end(), l) - q.begin();
int ri = lower_bound(q.begin(), q.end(), r) - q.begin();
while (l <= r) {
if (q[le] > r) {
le -- ;
res += (r - q[le]) * q[ ++ le];
break;
}
else if (l <= q[le]) {
res += (q[le] - l + 1) * q[le];
l = q[le] + 1;
le ++ ;
}
}
cout << res << endl;
return 0;
}