CF1029D Solution

题目链接

题解

如果\(k\)整除两个接起来的数\(a_i,a_j\),它们一定满足\(k|(a_i\cdot10^{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;
}
posted @ 2021-01-10 10:22  violet_holmes  阅读(61)  评论(0编辑  收藏  举报