整数拼接
题意
给n个整数,从里面选俩个整数,一前一后拼接成一个新数,若这个新数是k的倍数,那么res++。问res多少?
思路
首先暴力代码
for (int i = 0; i < n; i ++ )
for (int j = 0; j < n; j ++ )
if (check(a[i], a[j]))
ans ++ ;
第一重循环,去不了的情况下,我们试图优化第二重循环。
第二重循环,求的是:拼接结果a[i] 在前a[j]在后是k的倍数的个数。
我们把这个数用DP处理出来。
我们先默认a[i]在前,a[j]在后,那结果为:
(a[i]*10^(len(a[j])) + a[j] ) %k ==0
化解一下: a[i]*10^(len(a[j])) %k + a[j] %k ==0
当我们枚举到第j个数a[j]时,得知道j之前符合上面的数的个数。
可以定义f[i] [j] :为a[j] 之前的数,这些数^len(a[j]) 膜为j的个数。
把等式+左边的余数求出来,那我们就可以线性求出与等式+右边的余数之和为0的数。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define mst(s,_s) memset(s, _s, sizeof(s))
const double PI = acos(-1.0);
const double eps = 1e-6;
const int INF = 0x3f3f3f3f;
const int N = 1e6+100;
int a[N],T,n,m;
int f[13][N];
ll res=0;
int get(int x)
{
int res=0;
while(x){
x/=10;
res++;
}
return res;
}
void work()
{
for(int i=1;i<=n;i++)
{
res+=f[get(a[i])][(m-(a[i]%m))%m] ;
for(int j=1,t=10;j<11;j++)
{
f[j][1ll*a[i]*t%m] ++ ;
t=t*10%m;
}
}
}
int main() {
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
work();
memset(f,0,sizeof f);
reverse(a+1,a+n+1);
work();
cout<<res<<endl;
return 0;
}