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

题目传送门
题意:
给定n个数,将任意两个数连接起来。求有多少对这样的组合使得组合后的数能被k整除?
思路:
暴力肯定不行,暴力就是一个一个去组合,所以会超时。那我们换一种思路,给定一个数,寻找能与他匹配的数有多少个。这样只要n的复杂度,所以我们要预处理一下(我们就是巴一中漫无目的的寻找转化为有目的的寻找,暴力就是将两者绑定在一起然后才能判断,而预处理则是两者并没有必然联系,不会不可分离)。那么我们怎么将两者分开呢?比如1234 = 1200 + 34,我们分开算1200的余数,和34的余数,12后面有几个0,就是添加在他后面的数字的数位。那我们干脆直接求出每个数分别向左移动1-10位的余数。另外,要排除自己和自己组合的情况。
一个例子(帮助理解):
给出n个数和一个mod,求多少对加起来mod等于0?

这个n^2也不行,但是我们想一下如果我取余一个数=x 的话 我要什么情况才能让这个数加一个数%mod等于0,我们只有(x+y)%mod == 0 那在我们知道x的情况,我们只要找 mod-y的余数个数有多少即可。
还有一点提醒就是,这个可能会TLE,而且每次TLE的测试数据不固定,运气好就可以过,我就是AC了然后交AC代码有可能会TLE。
其他高手的链接

AC code:
#include<bits/stdc++.h> 
using namespace std;
typedef long long LL;
const int maxn = 2e5 + 10;
map<LL,LL> mp[11];//定义多维map 
int n = 0,k = 0;
LL a[maxn];
int main(){
    while(scanf("%d %d",&n,&k) != EOF){
        //mp.clear();
        for(int i = 0;i < 11;++i){//注意要清楚每个一维的map 
            mp[i].clear();
        }
        for(int i = 1;i <= n;++i){
            scanf("%I64d",&a[i]);
            LL x = a[i];
            for(int j = 1;j <= 10;++j){//预处理,每个数分别向左移动j位mod k 的余数,
                                        //方便后面直接查找 
                x *= 10;
                x %= k;
                ++mp[j][x];
            }
        }
        LL sum = 0;
        for(int i = 1;i <= n;++i){
            LL t = a[i] % k;
            int len = log10(a[i]) + 1;//求出该数的数位(也就是他加在其他数后面时,其他数移动的位数) 
            sum += mp[len][(k - t) % k];//查找移动len位,余数与t互补 
            LL x = 1;
            for(int j = 1;j <= len;++j){//排除是本身的情况 
                x = (x * 10) % k;
            }
            if(((a[i] * x)%k + a[i]%k)%k == 0){
                --sum;
            }
        }
        printf("%I64d\n",sum);
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值