加法方案
加法方案
Description
对于一个数字
- 从
n 中选出若干个数位(至少1 个); - 将选出的数位拼成一个新的数字;
- 将剩下的数位再拼成一个新的数字;
- 两个新数字的和为答案。
求所有拆数字的方案的答案之和,对
对于
对于
Solution 1
首先我们将输入的数字翻转,定义
接下来考虑每个数对答案的贡献。
对于第
由于
对于
第
暴力计算这个式子时间复杂度为
Solution 2
为了方便描述,我们将答案式写下来:
把与
问题来到了如何快速计算
由于用到的都是
如果你用程序打几个这样的数字的表,你会得到这样的结果:
1
11
121
1331
14641(指一万四千六百四十一)
神奇的是这些数字竟然就是杨辉三角!
我们将上面式子中的
那么问题就转换成了,如何把杨辉三角某一行上的数字按照上面的方式写下来。
我们定义
那么我们如如何快速地根据
考虑进行一个错位,并与原数相加。具体如图:
那么就得到下一行的值了。
考虑完成这个操作。把
可以看出的是,
整理一下,答案为:
于是预处理 吊打std
一些问题:
- 一个数字是可以被拆出来两次的,也就是说计算最终答案时需要将答案乘
2 。例如在123 这个例子中,如果最开始选出1 个数,有可能被分成2, 13 两个数,但如果最开始选出2 个数,仍然可能会分成这两个数。因此答案需要乘2 ; - 如果最开始将所有的数字都选出了,那么这个值的答案不需要乘
2 。因为题目要求求是不能选出0 个数的。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define re register
#define il inline
const int N = 100010, P = 998244353;
char s[N];
int a[N], res;
int n;
il int fpm(re int a, re int b)
{
re int res = 1;
while (b)
{
if (b & 1) res = (LL)res * a % P;
b >>= 1, a = (LL)a * a % P;
}
return res;
}
int p10[N], p11[N], p2[N];
il void init()
{
p10[0] = p11[0] = p2[0] = 1;
for (re int i = 1; i < N; ++ i )
p11[i] = p11[i - 1] * 11ll % P,
p2[i] = p2[i - 1] * 2ll % P,
p10[i] = p10[i - 1] * 10ll % P;
}
int k;
int main()
{
init();
scanf("%s", s);
n = strlen(s);
for (re int i = 1; i <= n; ++ i )
a[i] = s[n - i] - '0';
for (re int i = 1; i <= n; ++ i )
res = (res + (LL)a[i] * p2[n - i] % P * p11[i - 1] % P) % P;
res = res * 2ll % P;
for (re int i = 1; i <= n; ++ i )
res = ((res - (LL)a[i] * p10[i - 1] % P) % P + P) % P;
cout << res;
return 0;
}