#include<stdio.h>
#include<string.h>
#define maxn 50005
#define maxm 205
#define INF 0xfffffff
int number[maxn],digits[maxn];
int count[maxn][maxm],e[3*maxn];
int n,mod;
void init()
{
memset(count,0,sizeof(int)*n*maxm);//这里是maxm,如果直接把所有的都置0,会tle
// memset(count,0,sizeof(count));//这里会tle
for(int i=1;i<=3*n;i++)
{
e[i]=(e[i-1]*10)%mod;
}
}
inline int getdigits(int x)
{
if(x==0) return 1;
int ret=0;
while(x)
{
ret++;
x/=10;
}
return ret;
}
int main()
{
e[0]=1;
while(scanf("%d%d",&n,&mod)!=EOF)
{
init();
for(int i=0;i<n;i++)
{
scanf("%d",&number[i]);
digits[i]=getdigits(number[i]);
}
number[n]=number[0];
digits[n]=digits[0];
//count[i][s]表示以i结尾,余数为s的子串数
//先计算出count[0][s]
int s=0,ans=0,l=0;
for(int i=n;i;i--)
{
s=(s+e[l]*number[i])%mod;//从后向前一个一个增加
//余数是number[i]*前面数的长度加上原余数
l+=digits[i];
count[0][s]++;
}
ans+=count[0][0];//s是从1到0的子串的余数
for(int i=1;i<n;i++)
{
for(int r=0;r<mod;r++)
{
count[i][(r*e[digits[i]]+number[i])%mod]+=count[i-1][r];//从数的后面添加数
}
s=(s*e[digits[i]]+number[i])%mod;
//s最开始是从1-2-3-。。。-0 这以0结尾的子串取模的余数,然后在求以1结尾的余数
//count[i-1][r]表示的是前一个数字所有的子串,
//当然也包括从i-(i+1)-(i+1)-...-(n-1)-0-1-(i-1)这个子串,
//不过这个以(i-1)结尾的子串在尾部增加i的时候是不行的,因为已经在前面出现了i,
//所以得把这种情况减掉。
count[i][s]--;
//以number[i]单独为一个串
count[i][number[i]%mod]++;
//最低位插入i之后,更改s的值,即减掉最高位的i
s=((s-number[i]*e[l])%mod+mod)%mod;
ans+=count[i][0];//l的长度始终为总长度
}
printf("%d\n",ans);
}
return 0;
}
hdu 4669 开二维数组记录结尾点和余数求整除问题
最新推荐文章于 2024-01-21 19:40:28 发布