试题 历届试题 整数拼接(数位dp)
题目描述
给定一个长度为 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≤1e5
1≤K≤1e5
1≤Ai≤1e9
输入样例:
4 2
1 2 3 4
输出样例:
6
题解:
这是今年省赛第一场c++b组的题目,做完挺有收获的,这里记录一下,具体见代码注释。
#include<bits/stdc++.h> using namespace std; int cnt[15][100005]; long long a[100005]; int getbit(long long ans){ int res=0; do{ ans/=10; res++; }while(ans); return res; } long long pow(int bit){ long long ans=1; for(int i=1;i<=bit;i++){ ans*=10; } return ans; } int main(){ int n,k;scanf("%d%d",&n,&k); for(int i=0;i<n;i++){ scanf("%ld",&a[i]); cnt[getbit(a[i])][a[i]%k]++;//记录相同位数余数的数的数量 } long long res=0; for(int i=0;i<n;i++){ cnt[getbit(a[i])][a[i]%k]--;//不能和自己拼接 for(int j=1;j<=10;j++){///枚举拼接在后面的数的所有位数,则两数拼接前面的数需要相应乘以对应的位数, ///根据乘以相应位数得到的前面的数的余数情况推断后面的数需要满足的余数 if((a[i]%k*pow(j))%k==0){///特判一下取模结果为0 res+=cnt[j][0]; } else{ res+=cnt[j][k-(a[i]%k*pow(j))%k];//满足两个数的余数之和相加为k。 } } cnt[getbit(a[i])][a[i]%k]++;//恢复 } cout<<res<<endl; return 0; }