Date:2022.04.06
题意描述:
给定一个长度为 n 的数组 A1,A2,⋅⋅⋅,An。
你可以从中选出两个数 Ai 和 Aj(i 不等于 j),然后将 Ai 和 Aj 一前一后拼成一个新的整数。
例如 12 和 345 可以拼成 12345 或 34512。
注意交换 Ai 和 Aj 的顺序总是被视为 2 种拼法,即便是 Ai=Aj 时。
请你计算有多少种拼法满足拼出的整数是 K 的倍数。
输入格式
第一行包含 2 个整数 n 和 K。
第二行包含 n 个整数 A1,A2,⋅⋅⋅,An。
输出格式
一个整数代表答案。
数据范围
1≤n≤10^5,
1≤K≤10^5,
1≤Ai≤10^9
输入样例:
4 2
1 2 3 4
输出样例:
6
思路①:硬枚举
O
(
n
2
)
O(n^2)
O(n2)。
思路②:我们观察到拼成的两个数
A
i
A
j
A_iA_j
AiAj有以下性质:
(
A
i
∗
1
0
l
e
n
(
A
j
)
%
m
+
A
j
%
m
)
%
m
=
=
0
(A_i*10^{len(A_j)}\%m+A_j\%m)\%m==0
(Ai∗10len(Aj)%m+Aj%m)%m==0。
举个例子:
3465
%
35
=
=
0
3465\%35==0
3465%35==0,其中
3400
%
35
=
=
5
、
65
%
35
=
=
30
3400\%35==5、65\%35==30
3400%35==5、65%35==30;
3535
%
35
=
=
0
3535\%35==0
3535%35==0,其中
3500
%
35
=
=
0
、
35
%
35
=
=
0
3500\%35==0、35\%35==0
3500%35==0、35%35==0。
因此我们发现,用两个数拼接出来的数只有对
m
o
d
mod
mod取模相加再对
m
o
d
mod
mod取模为0时,或者对
m
o
d
mod
mod取模都为0且相等时才能整除
m
o
d
mod
mod。而这两种情况,可归结为取模相加再取模为0。
因此,我们对每个数
a
[
i
]
a[i]
a[i]找到它前面加上哪些数可以凑出
(
a
[
i
]
%
m
o
d
+
x
%
m
o
d
)
%
m
o
d
=
=
0
(a[i]\%mod+x\%mod)\%mod==0
(a[i]%mod+x%mod)%mod==0,也就是要找到所有
x
%
m
o
d
=
=
(
m
o
d
−
a
[
i
]
%
m
o
d
)
%
m
o
d
x\%mod==(mod-a[i]\%mod)\%mod
x%mod==(mod−a[i]%mod)%mod的、且能放到
a
[
i
]
a[i]
a[i]前面的(也就是恰好乘了
1
0
a
[
i
]
10^{a[i]}
10a[i]的数)。
由此,我们预处理出所有
c
[
i
]
[
j
]
:
c[i][j]:
c[i][j]:所有向左移
i
i
i位(也就是乘了
1
0
i
10^i
10i),且
%
m
o
d
\%mod
%mod为
j
j
j的数有多少个。
此外,注意题意要求下标不能相同,但
a
[
i
]
∗
1
0
a
[
i
]
a[i]*10^{a[i]}
a[i]∗10a[i]也有可能可以加到
a
[
i
]
a[i]
a[i]前,因此判断
(
a
[
i
]
%
m
o
d
+
1
0
a
[
i
]
%
m
o
d
)
%
m
o
d
=
=
0
(a[i]\%mod+10^{a[i]}\%mod)\%mod==0
(a[i]%mod+10a[i]%mod)%mod==0是否成立,若成立则说明他可以加到
a
[
i
]
a[i]
a[i]前,因此要把它去掉,-1。
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long LL;
const int N=1e5+10;
LL n,m,a[N],c[64][N],len[N];
LL q10(LL a,LL k,LL mod)
{
LL x=a;
for(int i=1;i<=k;i++) x=x*10%mod;
return x;
}
int main()
{
cin>>n>>m;memset(c,0,sizeof c);
for(int i=1;i<=n;i++)
{
cin>>a[i];string ss=to_string(a[i]);len[i]=ss.length();
LL x=a[i],cnt=0;
for(int j=1;j<=18;j++)
{
x=x*10%m;
c[++cnt][x%m]++;
}
}
LL ans=0;
for(int i=1;i<=n;i++)
{
if(c[len[i]][(m-a[i]%m)%m])
ans+=(c[len[i]][(m-a[i]%m)%m]);
if((q10(a[i],len[i],m)%m+a[i]%m)%m==0) ans--;
}
cout<<ans;
return 0;
}