题目传送门
题意:
给你 个数 ,让你挑两个数,把这两个数拼起来,例如 和 拼起来是 。
问拼起来的数是 的倍数的方案数。认为 和 是不同的方案。都满足 。
数据范围: 。
题解:
我们挑选的其实是 。
位数比较小,可以预处理出来。
因此我们就枚举 ,去寻找 。
后面的是可以预处理出来的。
感受:
这道题 和 都能做。
假如用 ,那得先 判定存在还是不存在。
如果不存在就去索引,那会慢很多。
代码:
#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int maxn = 2e5 + 5 ;
int n , k , a[maxn] , num[maxn] ;
ll ten[maxn] ;
map<int , int> mp[15] ;
void init()
{
for(int i = 1 ; i <= n ; i ++)
{
int x = a[i] ;
while(x > 0) x /= 10 , num[i] ++ ;
if(mp[num[i]].count(a[i] % k)) mp[num[i]][a[i] % k] ++ ;
else mp[num[i]][a[i] % k] = 1 ;
}
ten[0] = 1 ;
for(int i = 1 ; i <= 10 ; i ++)
ten[i] = ten[i - 1] * 10 % k ;
}
bool ok(int i)
{
ll y = ll(a[i]) * ten[num[i]] % k ;
y += a[i] , y %= k ;
return y == 0 ;
}
int cal(int i , int j)
{
ll x = a[i] ;
int y ;
int ans = 0 ;
x = x * ten[j] % k ;
y = k - (int) x ;
y %= k ;
if(mp[j].count(y)) ans += mp[j][y] ;
return ans ;
}
void solve()
{
ll ans = 0 ;
for(int i = 1 ; i <= n ; i ++)
for(int j = 1 ; j <= 10 ; j ++)
ans += cal(i , j) ;
for(int i = 1 ; i <= n ; i ++)
if(ok(i)) ans -- ;
printf("%lld\n" , ans) ;
}
int main()
{
scanf("%d%d" , &n , &k) ;
for(int i = 1 ; i <= n ; i ++) scanf("%d" , &a[i]) ;
init() ;
solve() ;
return 0 ;
}