2068. 整数拼接(蓝桥真题)

文章描述了一个编程问题,其中涉及计算两个数a和b连接后对给定数k取余的结果。通过分析,可以简化问题,只关注a和b对k取余的值和b的位数。通过枚举b的位数和余数,可以找到满足条件的b的个数。代码中使用动态规划数组f记录不同长度和余数的数的个数,并处理特殊情况,如a与自身连接的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

样例输入: 

4 2
1 2 3 4

样例输出:

6

分析:对于一个数a和b,我们要求a和b连接后的数对k取余的结果,我们可以对这个问题进行简化

假设a=p1*k+r1,b=p2*k+r2,b的长度为l,那么ab就等于a*10^l+b,那么ab%k=(a*10^l+b)%k=((p1*k+r1)*10^l+p2*k+r2)%k=(r1*10^l+r2)%k

那么也就是说我们只需要记录a和b对k取余后的值以及b的位数就可以知道ab连接后对k取余的值,假如说我们现在知道第一个数是a,他对k取余后的值为r1,现在让我们求一个1<=b<=10^9,使得ab连接后的数对k取余后的值为0,那么我们可以考虑枚举b的位数,也就是枚举l,其中b对k的余数为x,那么我们就有

(r1*10^l+x)%k=0,由于r1和l都是已知的,那么我们就可以求出x,那么对于所有的满足位数为l,且余数为x的数b都是满足题意的。

由上面的分析我们可以发现,对于一个数a,我们需要知道另一个数对k取余后的结果以及位数来判断另一个数是否满足题意,那么我们可以枚举所有的a,对于每一个a,直接枚举b的位数,然后求出所有满足余数的b的个数,这个我们是可以直接在输入a数组时进行统计的,所以这样就可以直接得到答案。需要统计的数组定义如下:

f[i][j]记录长度为j且对k取余后结果为i的数的个数 

需要注意的是如果a和他自己拼接之后满足是k的倍数,那么我们要对答案进行减1,防止多统计这种情况。

细节见代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
const int N=1e5+10;
int f[N][11];//f[i][j]记录长度为j且对k取余后结果为i的数的个数 
long long a[N],len[N];
long long ppow(long long a,long long b)
{
	long long ans=1;
	for(int i=1;i<=b;i++)
		ans*=a;
	return ans;
}
int main()
{
	int n,k;
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
		long long t=a[i];
		while(t)
		{
			t/=10;
			len[i]++;
		}
		f[a[i]%k][len[i]]++;
	}
	long long ans=0;
	for(int i=1;i<=n;i++)
	{
		long long r=a[i]%k;
		if((r*ppow(10,len[i])+r)%k==0) ans--;//防止自身与自身匹配
		for(int j=1;j<=10;j++)//枚举长度
		{
			long long tr=(r*ppow(10,j)%k);
			tr=(k-tr)%k;
			ans+=f[tr][j];
		}
	}
	printf("%lld\n",ans);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值