题解
如果(k)整除两个接起来的数(a_i,a_j),它们一定满足(k|(a_icdot10^{dig_j}+a_j)),其中(dig_j)为(a_j)的数位。由于求余运算的可加、乘性,(a_i,a_j)需要满足(k|[(a_i\%k)cdot(10^{dig_j}\%k)+a_j\%k]),也就是只需知道(a_i)、(10^{dig_j})、(a_j)模(k)的余数即可。可以发现(dig_j)是不确定的,因此需要将(a)数组依照数位划分,重新存入(mod)数组中。此外,枚举(a_j)的时间复杂度为(O(n^2)),因此需要将(mod)数组排序后二分查找,时间复杂度(O(nlogn))。还有,二分查找的结果可能会包含(a_i)本身,因此如果数位相同且(a_i)合法,(ans)需要(-1)。
AC代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10;
int a[N],mod[15][N],len[15],dig[N],pw[15],k;
//mod[i][j]:第j个数位为i的数,len[i]:数位为i数的个数,dig[i]:a[i]的数位,pw[i]:10^i模k的余数
void init()
{
pw[0]=1;
for(int i=1;i<=10;i++) pw[i]=pw[i-1]*10%k;
}//预处理pw数组
signed main()
{
int n,maxd=0,ans=0;
scanf("%lld%lld",&n,&k);
init();
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
int qwq=a[i];
while(qwq) {qwq/=10; dig[i]++;}
maxd=max(maxd,dig[i]);
mod[dig[i]][++len[dig[i]]]=a[i]%k;
}
for(int i=1;i<=maxd;i++) sort(mod[i]+1,mod[i]+len[i]+1);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=maxd;j++)
{
int qaq=(k-a[i]*pw[j]%k)%k;
int r=upper_bound(mod[j]+1,mod[j]+len[j]+1,qaq)-mod[j];
int l=lower_bound(mod[j]+1,mod[j]+len[j]+1,qaq)-mod[j];
ans+=r-l;
if(dig[i]==j && (a[i]*pw[j]+a[i])%k==0) ans--;
}
}
printf("%lld",ans);
return 0;
}