Codeforces Round #506 (Div. 3) D(数论 + 哈希)

探讨了在给定数组中寻找两数拼接后能被特定整数k整除的有效数对问题,通过预处理降低复杂度至接近O(nlogn),并提供了解决方案的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Concatenated Multiples

time limit per test 2 seconds

memory limit per test 256 megabytes

input standard input

output standard output

You are given an array a, consisting of n positive integers.

Let's call a concatenation of numbers x and y the number that is obtained by writing down numbers x and y one right after another without changing the order. For example, a concatenation of numbers 12 and 3456 is a number 123456.

Count the number of ordered pairs of positions (i,j) (i≠j) in array a such that the concatenation of ai and aj is divisible by k.

Input

The first line contains two integers n and k (1≤n≤2⋅105, 2≤k≤109).

The second line contains n integers a1,a2,…,an (1≤ai≤109).

Output

Print a single integer — the number of ordered pairs of positions (i,j) (i≠j) in array a such that the concatenation of ai and aj is divisible by k.

Examples

Input

6 11
45 1 10 12 11 7

Output

7

Input

4 2
2 78 4 10

Output

12

Input

5 2
3 7 19 3 3

Output

0

Note

In the first example pairs (1,2), (1,3), (2,3), (3,1), (3,4), (4,2), (4,3) suffice. They produce numbers 451, 4510, 110, 1045, 1012, 121, 1210, respectively, each of them is divisible by 11.

In the second example all n(n−1) pairs suffice.

In the third example no pair is sufficient.

题目大意:

       给定一系列的数,挑出两个数连起来后可以被题目中给定的 k 整除,这样的数可以有多少对?比如 2 “+” 7 “=” 27 可以被3 整除。

思路:

       直接暴力枚举的话,复杂度O(n^2)是一定不可以的,所以我们考虑一些预处理来求解的降低复杂度。对于两个数a、b,若要找有多少 b 使得 (a + b) % k = 0,则问题等价于找有多少个 k - a % k。

        回到这个问题,我们预处理每个数计算出它 mod k 的值 p,并算出它的长度 len,通过 m[len][p] 来计数。之后,对每个数 a[i] 枚举 t = a[i] * 1ej  % k (j=1,...,11),则 m[j][(k - t) % k] 就是 a[i] 右接一个长度为 j 的数所有正确的答案数。将整个数组过一遍,对所有正确的答案数求和就是最终的答案。复杂度接近 O(nlogn)。

代码:

#include<map>
#include<cmath>
#include<cstdio>
#define ll long long
using namespace std;
const int maxn = 2e5 +5;
map<ll,ll> m[20];
ll a[maxn];

int main()
{
    ll n,k;
    ll ans = 0;
    scanf("%I64d %I64d",&n,&k);
    for(int i = 0;i < n; ++i)
    {
        scanf("%I64d",&a[i]);
        ll p = a[i] % k;
        ll len = log10(a[i]) + 1;
        ll tp = a[i];
        m[len][p]++;
    }
    for(int i = 0;i < n; ++i)
    {
        ll p = a[i] * 10 % k;
        ll len = log10(a[i]) + 1;
        for(int j = 1;j < 11; ++j)
        {
            if(j == len && (k - p) % k == a[i] % k) --ans;// Delete itself
            ans += m[j][(k - p) % k];
            p = p * 10 % k;
        }
    }
    printf("%I64d\n",ans);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值