题目 2578: 蓝桥杯2020年第十一届省赛真题-整数拼接

给定一个长度为 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≤n≤105,
1≤K≤105,
1≤Ai≤109
输入样例:
4 2
1 2 3 4
输出样例:
6

Ai*(10^(len(Aj))+Aj,例如12和345拼起来就是12*(10^3)+345,它的余数(Ai*(10^(len(Aj))+Aj)%k就等于((Ai%k*(10^len(Aj)%k))%k + Aj%k)%k.    (len(Aj)表示Aj这个数的长度)

(Ai%k*(10^len(Aj)%k))%k,len(Aj)的长度必然是大于等于1,小于等于10的,而对k取余后,余数肯定小于k的范围,我们可以建立一张表,用来存放Ai乘10的不同次方(从1到10即可)对k取余的结果的个数,即b[r][(Ai%k*(10^r%k))%k],可知,第一个中括号的r范围是1-10,第二个中括号的范围是小于0-k。

再看第二项Aj%k,如果满足题目条件,那么((Ai%k*(10^len(Aj)%k))%k + Aj%k)%k=0,第一项和第二项的和一定是k(因为两者都小于k),k-Aj%k=(Ai%k*(10^len(Aj)%k))%k,我们如果在上面的表中找到b[len(Aj)][k-Aj%k],证明满足了题目条件,ans++就行 //本段解释照搬其它up主 懒得解释 偷下懒
 

满分ac 优化后

#include<bits/stdc++.h>
using namespace std;
int n;
int k;
long long  b[11][100005];
long long  a[100005];
int  ans=0;
void slove()
{
    for(int i=1;i<=n;i++)
    {
//a[i]在前 所以后面需要reverse 下面的%k是为了防止过大超出内存
        ans+=b[(int)log10(a[i])+1][(k-a[i]%k)%k];//如果存在则加一 此刻的[(k-a[i)%k)%k]里的a[i]其实相当于上一个循环的后一个数
        int pow=10;//计算j次方
        for(int j=1;j<=10;j++)
        {
            b[j][(a[i]%k*pow)%k]++;
            pow=pow*10%k;
        }
    }
}
int main()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    slove();
    reverse(a+1,a+n+1);
    memset(b,0,sizeof(b));
    slove();
    cout<<ans;
    return 0;
}

暴力求解 部分正确时间超限

#include<bits/stdc++.h>
using namespace std;
int n;
int k;
long long sum1;
long long sum2;
long long a[100005];
long long b[100005];
int cnt=0;
int slove()
{
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            
            
            sum1=a[i]*b[j]+a[j];
            sum2=a[j]*b[i]+a[i];
            
            if(sum1%k==0)
            cnt++;
            if(sum2%k==0)
            cnt++;
        }
    }
    return cnt;
}
int main()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i]; 
    }
    for(int i=1;i<=n;i++)
    {
        int ans=0;
        int m=a[i];
        while(m!=0)
        {
            ans++;
            m=m/10;
        }
        long long sum=1;
        for(int i=1;i<=ans;i++)
        {
            sum=sum*10;
        }
        b[i]=sum;
    }
    cout<<slove();
    return 0;
    
}

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值