大致题意:给定n个数字和p,选择一些将数字拼接成一个新的数字ans(可以重复选择),ans可被p整除.(n个数字长度总和<=1e6,p<=200 )
分析:参考jls代码..%%%九峰大佬..

  • 考虑p的范围不大,可以写动态规划并且对于每一个数而言模p下的贡献方案最多只有p次,那么我们只需要外层循环更新p次即可.
    ,dp[i]表示选择一些数字拼接后模p下余数为i的最小长度.那么我们枚举n个数进行更新dp[j]数组,对于当前第i个数而言更新dp[j],图片说明 表示第i个数字的长度,我们简化图片说明= 图片说明 ,x表示第i个数字模p下的答案,我们考虑将数字拼接到右边,那么新的数字模p下就是图片说明
    ,那么我们可列出转移方程:图片说明 ,now和pre我们可以用滚动数组维护.
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn=1e6+10;
const int mod=998244353;
const int inf=0x3f3f3f3f;
int n,p;
int dp[2][205];
int d[maxn],len[maxn],pw[maxn];



int main()
{
    scanf("%d%d",&n,&p);
    pw[0]=1;
    for( int i=1;i<maxn;i++ ) pw[i]=10*pw[i-1]%p;
    getchar();
    for( int i=1;i<=n;i++ )
    {
        char s=getchar();
        int cnt=0;
        for( ;isdigit(s);d[i]=(d[i]*10+s-48)%p,cnt++,s=getchar());
        len[i]=cnt;
    } 
    int now=1;
    for( int i=1;i<p;i++ ) dp[0][i]=inf;
    for( int i=1;i<=p;i++ )
    {
        for( int j=0;j<p;j++ ) dp[now][j]=dp[now^1][j];
        if( dp[now][0]==0 ) dp[now][0]=inf;
        for( int j=1;j<=n;j++ )
        {
            for( int k=0;k<p;k++ )
            {
                dp[now][ (k*pw[len[j]]+d[j])%p ]=min( dp[now][ (k*pw[len[j]]+d[j])%p ],dp[now^1][k]+len[j] );
            }
        }
    //    for(int j=0;j<p;j++)cout<<dp[now][j]<<' ';cout<<endl;
        now^=1; 
    }
    if( dp[now^1][0]>=inf ) printf("-1");
    else printf("%d\n",dp[now^1][0]);
    return 0;
}