题目描述
给定义个长度为 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。
【输出格式】
一个整数代表答案。
样例输入
4 2
1 2 3 4
样例输出
6
【评测用例规模与约定】
对于 30% 的评测用例,1≤n≤1000,1≤K≤20,1≤Ai≤104。
对于所有评测用例,1≤n≤105,1≤K≤105,1≤Ai≤109。
别人的思路好妙
将所有的数扩大几倍对k%存起来,再将这个数求余k后的数和他的数位存起来,对于一个拼接好的数,组成它的两个数加起来%k等于0才算一对,一个数a【i】,它扩大几个10倍就代表和它拼接的数有几位,用一个mid表示和a【i】拼接的数,mid可能有很多个数取k的模得到,所以只要那个数的数位和a【i】扩大的倍数相同,就可以组成一对,最后,如果一个a[i]正好等于k减去a[i]的倍数时,应该将ans–,因为这代表a[i]与它本身拼接
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<queue>
#include<algorithm>
using namespace std;
const int N=1e5+5;
typedef long long ll;
int vis[N][11];
ll a[N][11];
int sw(int x)
{
int ans=0;
while(x)
{
ans++;
x/=10;
}
return ans;
}
int main()
{
int n,k,i,j,x;
ll ans=0;
scanf("%d%d",&n,&k);
for(i=0;i<n;i++)
{
scanf("%d",&x);
a[i][0]=x;
vis[x%k][sw(x)]++;
for(j=1;j<=10;j++)
a[i][j]=a[i][j-1]*10%k;
}
for(i=0;i<n;i++)
{
for(j=1;j<=10;j++)
{
int mid=(k-a[i][j])%k;
ans+=vis[mid][j];
if(a[i][0]%k==mid&&sw(a[i][0])==j)
ans--;
}
}
printf("%lld\n",ans);
return 0;
}
我的超时代码
//3880
//52038720
//10
//241830
//512
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
using namespace std;
char s1[30],s2[30];
int a[100005];
int main()
{
int n,k,q,w,i,j,l,c,m,ans=0;
scanf("%d%d",&n,&k);
for(i=0;i<n;i++)
scanf("%d",&a[i]);
for(i=0;i<n;i++)
{
for(j=i+1;j<n;j++)
{
if(i==j) continue;
l=0;
q=a[i];
w=a[j];
while(q)
{
s1[l++]=q%10+'0';
q/=10;
}
// l--;
while(w)
{
s1[l++]=w%10+'0';
w/=10;
}
m=0;
for(c=l-1;c>=0;c--)
{
m=m*10+s1[c]-'0';
m%=k;
}
if(m==0) ans++;
q=a[j];
w=a[i];
l=0;
while(q)
{
s2[l++]=q%10+'0';
q/=10;
}
// l--;
while(w)
{
s2[l++]=w%10+'0';
w/=10;
}
m=0;
for(c=l-1;c>=0;c--)
{
m=m*10+s2[c]-'0';
m%=k;
}
if(m==0) ans++;
}
}
printf("%d\n",ans);
return 0;
}