先求a[n-1]和a[0]不连接的 用dp可以求 dp[i][j]表示第i为余数为j 这里用了滚动数组。。
再处理a[n-1]和a[0]相连的 枚举终点 然后将前缀(en[i]表示的就是i~n-1这个前缀的余数)整个的搬到后缀中 通过余数拼接统计
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define clr(a,b) memset(a,b,sizeof(a))
typedef __int64 lld;
const int maxn = 50010;
int dp[2][210];
int en[maxn];
int dig[maxn];
int a[maxn];
int getdig(int n)
{
int res=1;
while(n)
{
n/=10;
res*=10;
}
return res;
}
int main()
{
int n,k;
while(~scanf("%d%d",&n,&k))
{
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
dig[i]=getdig(a[i]);
}
int now=0;
clr(dp,0);
dp[0][a[0]%k]=1;
lld ans=dp[0][0];
//0~n-1部分
for(int i=1;i<n;i++)
{
clr(dp[now^1],0);
dp[now^1][a[i]%k]=1;
for(int j=0;j<k;j++)
{
if(!dp[now][j]) continue;
int t=(j*dig[i]+a[i])%k;
dp[now^1][t]+=dp[now][j];
}
now^=1;
ans+=dp[now][0];
}
//处理出以i开头,n-1结尾 部分的余数
en[n-1]=a[n-1]%k;
int S=dig[n-1]%k;
for(int i=n-2;i>=0;i--)
{
en[i]=(a[i]*S%k+en[i+1])%k;
S=S*dig[i]%k;
}
//处理n-1和0连接的部分
S=dig[0]%k;
int r=a[0]%k;
for(int i=0;i<n-1;i++)
{
dp[now][en[i]]--;
for(int j=0;j<k;j++)
{
int t=(j*S+r)%k;
if(t==0) ans+=dp[now][j];
}
S=S*dig[i+1]%k;
r=(r*dig[i+1]+a[i+1])%k;
}
printf("%I64d\n",ans);
}
}