题目描述
难度分:844
输入n(2≤n≤2×105)和长为n的数组a(1≤a[i]≤109)。
定义f(x,y)表示拼接x和y得到的数字,例如f(3,14)=314。
输出所有f(a[i],a[j])之和,其中i<j。答案模998244353。
输入样例1
3
3 14 15
输出样例1
2044
输入样例2
5
1001 5 1000000 1000000000 100000
输出样例2
625549048
算法
前后缀分解
枚举前缀的x∈a,即x=a[i],i∈[1,n−1],这时候需要知道[i+1,n]上每一个数字有多长,对于一个长度为len的数字a[j],a[i]与它拼起来的结果就是a[i]×10len+a[j]。因此a[i]与后面的数字拼接之后的总和分为两个部分,第一个部分就是后缀和Σj∈[i+1,n]a[j],第二个部分就是Σlena[i]×10len,其中len就是后缀[i+1,n]每个数字的长度,由于a[i]≤109,所以len≤10,可以用一个哈希表counter维护后缀每个长度的数字有多少个。
复杂度分析
时间复杂度
遍历a[i]的时间复杂度为O(n)。而对于每个a[i],需要遍历counter表,counter表的大小与a数组中每个数字的长度有关,在最差情况下长度为1到10的数字都有,时间复杂度为O(log10U),其中U是数组a的值域。因此,整个算法的时间复杂度为O(nlog10U)。
空间复杂度
counter表在最差情况下大小为10,空间复杂度为O(log10U)。除此之外还有sz数组,sz[i]表示a[i]的长度,空间复杂度为O(n)。因此瓶颈在于sz数组,整个算法的额外空间复杂度为O(n)。
C++ 代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 200010, MOD = 998244353;
const LL p[11] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000ll};
int n, a[N], sz[N];
int main() {
scanf("%d", &n);
unordered_map<int, int> counter;
int tot = 0;
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
tot = (tot + a[i]) % MOD;
int num = a[i];
while(num > 0) {
sz[i]++;
num /= 10;
}
counter[sz[i]]++;
}
int ans = 0;
for(int i = 1; i < n; i++) {
counter[sz[i]]--;
if(counter[sz[i]] == 0) {
counter.erase(sz[i]);
}
tot = ((tot - a[i]) % MOD + MOD) % MOD;
ans = (ans + tot) % MOD;
for(auto&[len, cnt]: counter) {
ans = (ans + p[len] * cnt % MOD * a[i] % MOD) % MOD;
}
}
printf("%d\n", ans);
return 0;
}