整数拼接(枚举,哈希表,数学)

该博客介绍了如何使用哈希表解决一个数组元素两两拼接形成新整数,判断这个整数是否为给定数K的倍数的问题。通过建立10个哈希表来存储数组元素的每一位乘以10的幂次后的模K值,然后遍历数组,计算每个元素拼接后的模K值,从而找出符合条件的拼接方式。博客中还特别提到了负数取模的处理方法,并给出了完整的AC代码实现。
摘要由CSDN通过智能技术生成

题目链接:https://www.acwing.com/problem/content/2070/

题目
给定一个长度为 n n n 的数组 A 1 , A 2 , ⋅ ⋅ ⋅ , A n A_1,A_2,⋅⋅⋅,A_n A1,A2,,An

你可以从中选出两个数 A i A_i Ai A j A_j Aj(i 不等于 j),然后将 A i A_i Ai A j A_j Aj 一前一后拼成一个新的整数。

例如 12 12 12 345 345 345 可以拼成 12345 12345 12345 34512 34512 34512

注意交换 A i A_i Ai A j A_j Aj 的顺序总是被视为 2 种拼法,即便是 A i = A j A_i=A_j Ai=Aj 时。

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

输入格式
第一行包含 2 2 2 个整数 n n n K K K

第二行包含 n n n 个整数 A 1 , A 2 , ⋅ ⋅ ⋅ , A n A_1,A_2,⋅⋅⋅,A_n A1,A2,,An

输出格式
一个整数代表答案。

数据范围
1 ≤ n ≤ 1 0 5 , 1≤n≤10^5, 1n105,
1 ≤ K ≤ 1 0 5 , 1≤K≤10^5, 1K105,
1 ≤ A i ≤ 1 0 9 1≤A_i≤10^9 1Ai109

输入样例:

4 2
1 2 3 4

输出样例:

6
思路:

A j A i A_jA_i AjAi拼接起来的数可以表示为 A j l e n ( A i ) + A i A_j^{len(A_i)}+A_i Ajlen(Ai)+Ai
因为是 K K K的倍数,所以有 A j l e n ( A i ) + A i = 0 ( m o d   k ) A_j^{len(A_i)}+A_i = 0 \quad (mod\ k) Ajlen(Ai)+Ai=0(mod k)
A j l e n ( A i ) = − A i ( m o d   k ) A_j^{len(A_i)}= -A_i \quad (mod\ k) Ajlen(Ai)=Ai(mod k)
可以用十个哈希表存储 A j ∗ 1 0 t , t ∈ [ 1 , 10 ] A_j * 10^{t},t \in [1,10] Aj10tt[1,10] k k k 的值
接着只需要枚举每个 A i A_i Ai,看有多少个 A j l e n ( A i )   %   k = − A i   %   k A_j^{len(A_i)} \ \%\ k = -A_i \ \%\ k Ajlen(Ai) % k=Ai % k 即可
注意:
①因为负数取模,c++中得到的是负数,数学上定义的是正数
比如
− 5   %   2 = − 3 ∗ 2 + 1 -5 \ \%\ 2 = -3 * 2 + 1 5 % 2=32+1 因此 − 5   %   2 = 1 -5 \ \%\ 2 = 1 5 % 2=1
− 1   %   4 = − 1 ∗ 4 + 3 -1 \ \%\ 4 = -1 * 4 + 3 1 % 4=14+3 因此 − 1   %   4 = 3 -1 \ \%\ 4 = 3 1 % 4=3
要取得 − a   %   k -a \ \%\ k a % k 的正数,即 ( k − a )   %   k (k - a) \ \%\ k (ka) % k

A j A_j Aj A i A_i Ai是同一个数的情况,即 j = i j = i j=i,答案要减1

AC代码

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

typedef long long LL;

const int N = 100010;

LL n,k,ans;
int arr[N],s[11][N];

int main()
{
    scanf("%lld%lld",&n,&k);
    for(int i = 0; i < n; i++)
    {
        scanf("%d",&arr[i]);
        LL t = arr[i] % k;
        t = t * 10 % k; // 从10^1开始
        for(int j = 1; j < 11; j++)
        {
            s[j][t]++;
            t = t * 10 % k;
        }
    }
    for(int i = 0; i < n; i++)
    {
        LL t = arr[i] % k;
        LL mod = (k - t) % k; //因为负数取模,c++中得到的是负数,要取得正数
        int len = to_string(arr[i]).size();
        ans += s[len][mod];
        LL r = t;
        while(len--) r = r * 10 % k;
        if(r == mod) ans --;
    }
    printf("%lld\n",ans);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值