版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
正题
首先我们可以发现一段区间的答案等于:
,其中Si指的是a的前缀和。
那么我们把a_i转成p进制,发现从l往r加ai,如果存在一次加法有进位,那么说明这一位的C变成了0,f必为0。
如果没有0,我们把ai转成p进制,把非0位用邻接表存下来,每次对于一个l暴力往右扩展就可以了。
时间复杂度是有保证的,因为每一位最多加p-1,一共有位,所以时间复杂度就是
实际上是跑不满的,但是可以构造卡满的数据,卡满这东西也不超过70000000.
0的情况特殊处理就可以了,具体可以自己想一想。(考虑什么情况下f相同)
#include<bits/stdc++.h>
using namespace std;
const int N=500010;
long long a[N];
int tmp[64],l[N];
struct node{
int x,t,next;
}s[N*64];
int first[N],len;
int n;
long long fac[10];
long long ans=0,mod;
long long C(int x,int y){
return fac[x]/fac[y]/fac[x-y]%mod;
}
void read(long long&x){
char ch=getchar();x=0;
while(ch<'0' || ch>'9') ch=getchar();
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
}
int main(){
scanf("%d %lld",&n,&mod);
fac[0]=1;for(int i=1;i<=mod-1;i++) fac[i]=fac[i-1]*i;
int t=0,last=0;
long long x,tot,f;
for(int i=1;i<=n;i++){
read(x);
if(x) l[++t]=last,ans+=last*(last+1)/2,last=0,a[t]=x;
else last++;
}
n=t;
if(last) l[++t]=last,ans+=last*(last+1)/2;
int mmax=0;
for(int i=1;i<=n;i++){
x=a[i];t=0;
while(x!=0){
if(x%mod) s[++len]=(node){t,x%mod,first[i]},first[i]=len,mmax=max(mmax,t);
x/=mod;t++;
}
}
for(int i=1;i<=n;i++){
tot=1;
for(int j=0;j<=mmax;j++) tmp[j]=0;
for(int j=i;j<=n;j++){
f=1;
bool we=true;
for(int k=first[j];k;k=s[k].next){
tmp[s[k].x]+=s[k].t;
if(tmp[s[k].x]>=mod) {we=false;break;}
tot=tot*C(tmp[s[k].x],s[k].t),tot>1e16?tot%=mod:0;
}
if(!we) break;
tot%=mod;
ans+=1ll*(l[i]+1)*(l[j+1]+1)*tot;
}
}
printf("%lld\n",ans);
}