CF1029D Solution

题目链接

题解

如果(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;
}
原文地址:https://www.cnblogs.com/violetholmes/p/14257497.html