整数拼接【维度为10的k次方,模数的DP】【蓝桥杯】

整数拼接

题意

给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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值