整数拼接

整数拼接

给定一个长度为 $n$ 的数组 $A_{1},A_{2}, \dots ,A_{n}$。

你可以从中选出两个数 $A_{i}$ 和 $A_{j}$ ($i$ 不等于 $j$),然后将 $A_{i}$ 和 $A_{j}$ 一前一后拼成一个新的整数。

例如 $12$ 和 $345$ 可以拼成 $12345$ 或 $34512$。

注意交换 $A_{i}$ 和 $A_{j}$ 的顺序总是被视为 $2$ 种拼法,即便是 $A_{i}=A_{j}$ 时。

请你计算有多少种拼法满足拼出的整数是 $K$ 的倍数。

输入格式

第一行包含 $2$ 个整数 $n$ 和 $K$。

第二行包含 $n$ 个整数 $A_{1},A_{2}, \dots ,A_{n}$。

输出格式

一个整数代表答案。

$1 \leq n \leq {10}^{5}$,
$1 \leq K \leq {10}^{5}$,
$1 \leq A_{i} \leq {10}^{9}$

输入样例:

4 2
1 2 3 4

输出样例:

6

 

解题思路

  很容易想到两个数两个数去枚举,但这样的时间复杂度是$O \left( n^{2} \right)$的,因此需要进行优化。

  我们任意选择两个数$x$,$y$,对其进行拼接,得到$x \times {10}^{s} + y$,其中$s = len \left( y \right)$,即数字$y$的位数。我们要找的是有多个这样形式的数,满足$x \times {10}^{s} + y \equiv 0 ~ \left( mod~K \right) $。

  我们可以通过枚举每一个数,把这个数当作上式的$y$,这时$y$和$s$都是一个确定的值,只需查看有多少个$x$,满足$x \times {10}^{s} + y \equiv 0 ~ \left( mod~K \right) $,进行一下变化,即有多少个$x$满足$x \times {10}^{s} \equiv -y ~ \left( mod~K \right) $。

  我们可以进行预处理,用哈希表来统计每一个数乘上${10}^{n}$后模$K$得到的余数的次数。这里$n = 1, 2, \dots , 10$,每一个数都要取。原理是开$10$个哈希表,然后用第$n$个哈希表来统计每个数乘上${10}^{n}$后模$K$得到的余数的次数。

  预处理完后,当再枚举每一个数$y$时,我们就可以直接查第$len \left( y \right)$个哈希表,查看有多少个数乘上$10$的$len \left( y \right)$次方后,$mod ~ K$后是$-y$的(当然,这里要转换为非负的余数)。

  当然,如果$y$这个数乘上$10$的$len \left( y \right)$次方模$K$等于$-y$,即$y \times {10}^{s} + y \equiv 0 ~ \left( mod~K \right) $,那么我们的结果要减去一个$1$,因为在预处理的时候,我们是把这种情况也统计进去的。

  AC代码如下:

 1 #include <cstdio>
 2 #include <string>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 typedef long long LL;
 7 
 8 const int N = 1e5 + 10;
 9 
10 int a[N], cnt[15][N];
11 
12 int main() {
13     int n, m;
14     scanf("%d %d", &n, &m);
15     for (int i = 0; i < n; i++) {
16         scanf("%d", a + i);
17         
18         LL t = a[i] % m;
19         for (int i = 1; i <= 10; i++) {
20             t = t * 10 % m;
21             cnt[i][t]++;    // 统计得到每个数的余数的次数
22         }
23     }
24     
25     LL ret = 0;
26     for (int i = 0; i < n; i++) {
27         int len = to_string(a[i]).size();
28         ret += cnt[len][(-a[i] % m + m) % m];
29         
30         LL t = a[i] % m;
31         while (len--) {
32             t = t * 10 % m;
33         }
34         if (t == (-a[i] % m + m) % m) ret--;    // 除去这个数本身进行拼接的次数
35     }
36     
37     printf("%lld", ret);
38     
39     return 0;
40 }

 

参考资料

  AcWing 2068. 整数拼接(蓝桥杯C++ AB组辅导课):https://www.acwing.com/video/2024/

posted @ 2022-03-22 19:22  onlyblues  阅读(324)  评论(0编辑  收藏  举报
Web Analytics