AtCoder AT_abc407_c [ABC407C] Security 2
题目大意
有一个空串 t t t 和一个目标串 S S S,每次执行下面两个操作中的任意一个:
- 在 t t t 的末位添一个 0 0 0,如 407 407 407 变成 4070 4070 4070。
- 将 t t t 中的所有数字变成它的“下一个”,其中“ a a a 的下一个( a a a 是数字)”指的是 ( a + 1 ) mod 10 (a+1)\operatorname{mod} 10 (a+1)mod10 的值。例: 1029 1029 1029 变成 2130 2130 2130。
问最少多少次操作可以达到目标串。
思路
为了方便,我们令 N N N 表示 S S S 的长度。
观察数据范围, N ≤ 5 × 10 5 N\le5\times10^5 N≤5×105 很大,需要一个 O ( N ) O(N) O(N) 的做法。然后我们发现了一个突破点:每添加一个数字之后,必须立刻调整整个数组的大小,然后再添加下一个。那么现在问题就转化为了求每一次需要调整多少次。
显然,当数组长度为 i i i 的时候,一定与第 i i i 个数和第 i + 1 i+1 i+1 个数有关。发现是求差的关系(因为具体的值在最后一次添加后可以调整,但是差必须马上确定)。然后,我们来考虑一下最后一次添加后应该怎么调整。现在,我们得到了前 N − 1 N-1 N−1 个数的“相对数列”——所有的差都是固定的了,但是值随着最后的一组调整而改变。实际上,第 N − 1 N-1 N−1 个数和第 N N N 个数的差也已经固定了,所以不用重复计算。那么需要的添加次数就是目标串中第 N N N 个数字的值。
代码
AC 记录:Submission #66099456。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;int n; string s;
int f[500010];int main()
{cin >> s;n = s.size();s = " " + s + "0";for (int i = 1; i <= n; i++)f[i] = f[i - 1] + (s[i] - s[i + 1] + 10) % 10;cout << f[n] + n << endl;return 0;
}
总结
难度大约 普及 − \color{orange} 普及- 普及−。