题目描述

给定一个长度为 n 的数组 A1​,A2​,⋯,An​。你可以从中选出两个数 Ai​ 和 Aj​(i=j),然后将 Ai​ 和 Aj​ 一前一后拼成一个新的整数。例如 12 和 345 可以拼成 12345 或 34512。注意交换 Ai​ 和 Aj​ 的顺序总是被视为 2 种拼法,即便是 Ai​=Aj​ 时。

请你计算有多少种拼法满足拼出的整数是 K 的倍数。

输入格式

第一行包含 2 个整数 n 和 K。

第二行包含 n 个整数 A1​,A2​,⋯,An​。

输出格式

一个整数代表答案。

输入输出样例

输入 #1复制运行

4 2
1 2 3 4

输出 #1复制运行

6

说明/提示

对于所有评测用例,1≤n≤105,1≤k≤105,1≤Ai​≤109。

蓝桥杯 2020 第一轮省赛 B 组 I 题。

题意

很好理解,挑两个数拼起来看是不是k的倍数,直接暴力枚举嘛!O(n的平方) 哦吼!!超时啦!

那那那那那........怎么办

我们来想一个问题

一个数与另一个数拼起来,怎么变成加起来呢?比如1和2怎么拼 是不是就是在1后面加上2的位数个0呀 也就是10 + 2 = 12,变成加法就好判断是不是k的倍数了嘛

a%k==n,b%k==m,若n+m==k(或者n和m都为0),则(a+b)%k==0,这个不用多说了吧

那么我们就可以将查找变成O(1)啦

我们定义一个二维数组ys[i][j] i代表位数,j代表余数

相信大家知道怎么预处理好数组,先算这个数的位数,再求这个数对k取余,放进去就好了嘛

我们来看样例

4 2

1 2 3 4

枚举每一个数,例如当前是1,我们首先找个数为1的数一直到个数为10的数

找个数为1的数 也就是让1*pow(10,1) 也就是10,样例中k是2,10%2=0,那么我们只要找到位数为1且余数为0有多少个不就可以了嘛

也就是ys[1][0]

全部统计起来就是答案

注意i!=j所以枚举每个数之前先将自己减去,统计完再加回来,而且不需要考虑交换,对于每个数除去了自己,就已经包括了所有交换顺序的情况

ac代码

#include<bits/stdc++.h>
using namespace std;
long long n,k,x,ans,sum;
long long ys[15][100005];
long long a[100005];
int main(){
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        //求每个数的位数,以及对k取余,放入ys数组中
        x=a[i];
        ans=0;
        while(x>0){
            x/=10;
            ans++;
        }
        ys[ans][a[i]%k]++;
    }
    for(int i=1;i<=n;i++){
        //每次找之前需要先除掉自己,因为题目要求i!=j
        x=a[i];
        ans=0;
        while(x>0){
            x/=10;
            ans++;
        }
        ys[ans][a[i]%k]--;
        for(int j=1;j<=10;j++){
            x=a[i]*pow(10,j);
            if(x%k==0){
                sum+=ys[j][0];
            }else{
                sum+=ys[j][k-x%k];
            }
        }
        //统计完之后再复原
        ys[ans][a[i]%k]++;
    }
    cout<<sum;
}

很简单吧!!!创作不易!!!求支持!!!点赞!!!

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐