Codeforces #506 D. Concatenated Multiples

D. 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⋅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

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整除,问共有多少种拼接方式。

思路

    这道题并没有可数学简化的地方,只有遍历计算一条路。

    假设a拼接到bn位数b的左边,得到的数是a*10^bn+b,若 a*10^bn+b mod k == 0 则计数+1.

    然而暴力遍历是O(n^2),难点就是如何将时间复杂度降到O(nlogn)。

    遍历a时,从 a*10^bn+b mod k == 0 可以看到如果固定bn,b的取值就被固定。如果把b按bn分类搜索,就只要对每个bn查找固定值b。

    提到查找固定值个数,容易想到哈希表和有序结构两种方式,但k过大,不考虑哈希表。

    multiset插入和查找时间复杂度是O(logn)。使用multiset优化后插入加遍历复杂度最坏不超过O(n*(logn+9log(n/9))),但可能常数过大,会TLE。换用vector排序就能过。

  • 0<bn<11,对10^bn的结果预计算可节约时间

代码

#include<bits\stdc++.h> 
typedef long long ll;
using namespace std; 
const int MAX=2e5+5;

int a[MAX];        //input
int len[MAX];      //len of ai
int mt[11];        //(10^i)%k
vector<int> d[11]; //a's of len i

int main(){
	int n,k;
	cin>>n>>k;
	int t=10%k;
	for(int i=1;i<11;i++){
		mt[i]=t;
		t=(10*t)%k;
	}
	for(int i=0;i<n;i++){
		int t,c=0;
		cin>>t;
		a[i]=t%k;
		while(t){
			c++;
			t/=10;
		}
		len[i]=c;
		d[c].push_back(a[i]);
	}
	ll cnt=0;
	for(int i=1;i<11;i++)
		sort(d[i].begin(),d[i].end());
	for(int i=0;i<n;i++){
		for(int j=1;j<11;j++){
			int t=k-((ll)a[i]*mt[j])%k;
			if(t==k) t=0;
			cnt+=(upper_bound(d[j].begin(),d[j].end(),t)-lower_bound(d[j].begin(),d[j].end(),t));
			if(len[i]==j && a[i]==t) cnt--;
		}
	}
	cout<<cnt;
	return 0;
}

http://www.cnblogs.com/hizcard/  转载请注明出处 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值