Codeforces Round #506 (Div. 3) D. Concatenated Multiples 数论

题目链接
题意:
给你一个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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值