题目链接
题意:
给你一个n个数和k(1 <= n <= 2e5 && 2 <= k <= 1e9)。
现在可以随意将俩个数结合如: 12 与 56 结合成1256。
现在问,有多少对数结合后能被k整除。(自身不能与自身结合)
思路:
首先,看见这么大的数据,暴力肯定是过不去的。必须在先前做一个预处理,使得到最后去寻找一对数的时候,时间复杂度为O(n),那么就想想这个预处理怎么做?这个主要就是考数学了,我们可以先分别对每个数模k,剩下的余数,如果其中一个余数乘以另一个数的余数的总位数(一共有多少位的10的总位数次方)再加上那个余数模去k等于0那么说明这种组合是可以的。那么我们就可以用map标记数字的长度,和这个数,以及这个数字的数量。最后再特判一下是不是与自身结合就行了。
//如果不清楚看代码叭。。。
这里博主语言表述不是很强,如果有兴趣,看看代码叭。本来自己都已经想得这么清楚了,但是不知道代码怎么写。咦,自己在这种题上还是差火候,昨天的codeforce和Atcoder也是都卡在这种题上了。思维有,就是代码写上去就是有bug,还得哭练
一个题,不仅考思维,还要考代码的写法以达到最佳。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
map<ll,ll> mp[20];//我不知道还有这种map的用法。。。太菜了
int main()
{
std::ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
ll n,k,sum = 0;
cin >> n >> k;
ll arr[n+5] = {0};
for(int i = 0;i < n;i++)
{
cin >> arr[i];
ll num = arr[i];
for(int j = 1;j <= 10;j++)
{
num *= 10;
num %= k;
mp[j][num]++;//标记这种数有多少个
}
}
for(int i = 0;i < n;i++)
{
ll a = log10(arr[i])+1;//这个余数有多少位
sum = sum + mp[a][(k-arr[i]%k)%k];//mp中这个位数的数,满足俩者 结合为k的整数倍的数
ll x = 1;
for(int j = 1;j <= a;j++)
x = x*10%k;//这里模不模k都可以,但是不能用pow,因为pow返回的是double类型,有精度误差,很容易出错,就比如样例中的第三例子,答案出来就是-1,就是pow的问题。
if(((arr[i]*x) % k + arr[i] % k) % k == 0) sum--;//特判自己与自己能不能结合
}
cout << sum << endl;
}