Codeforces Round #506 (Div. 3) D. Concatenated Multiples

http://codeforces.com/contest/1029/problem/D 

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⋅10^5, 2≤k≤10^9).

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

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

 这道题真的是厉害了,起初想不出来怎么做,除了暴力毫无思路,比赛结束后看了评论里的思路,实现了一下,花式超时。

思路:

先取模再相加和相加后再取模结果是一样的。因为要拼接,所以每个数字当它是前面那个的时候向左移动的位数是取决于后面的那个数字,于是每个数字都有可能向前移动0-10位。

代码中的各个数组含义:a输入的数字;w对应输入数字的位数;b[i]10^i mod k;

mod数组比较关键,计算完后,mod[i][j]表示所有数向左移i位对k求余是j的个数有多少。这样最后遍历一遍所有的数就可以直接查这个表得到相应的数。最后一遍遍历的时候要将同时将一个数左移再拼接这个数自己的情况减掉(最后一个for循环中的两个if)。

 

之前的思路复杂一些,最后根据评论中大神写法改成了这个思路还是超时。。。。又继续优化,写代码时候要注意好的习惯T_T

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<map>
using namespace std;
int a[200001],w[200001],b[11];
map<int,int>mod[11];
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);

    b[0]=1;

    for(int i=1;i<15;i++)
    {
        b[i]=(b[i-1]*10)%k;
    }
    for(int i=0;i<n;i++)
    {

        scanf("%d",&a[i]);
        int t=a[i];
        w[i]=0;
        while(t)
        {
            t=t/10;
            w[i]++;
        }
        a[i]=a[i]%k;
        for(int j=1;j<=10;j++)
        {
            mod[j][(long long)a[i]*b[j]%k]++;
        }
    }
    long long sum=0;
    int z;
    for(int i=0;i<n;i++)
    {
        sum+=mod[w[i]][(k-a[i])%k];
        if(a[i]==0) sum--;
        if((long long)a[i]*b[w[i]]%k==k-a[i]) sum--;
    }
    printf("%lld",sum);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值