混乱度,X Round 4 Div1 T3,数论 Lucas

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/Deep_Kevin/article/details/102675575

正题

      首先我们可以发现一段区间的答案等于:

      f(l,r)=\sum_{i=l}^rC_{S_i-S_{l-1}}^{a_i},其中Si指的是a的前缀和。

       那么我们把a_i转成p进制,发现从l往r加ai,如果存在一次加法有进位,那么说明这一位的C变成了0,f必为0。

       如果没有0,我们把ai转成p进制,把非0位用邻接表存下来,每次对于一个l暴力往右扩展就可以了。

       时间复杂度是有保证的,因为每一位最多加p-1,一共有\log_p w位,所以时间复杂度就是O(n*(p-1)\log_pw)

       实际上是跑不满的,但是可以构造卡满的数据,卡满这东西也不超过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);
}

猜你喜欢

转载自blog.csdn.net/Deep_Kevin/article/details/102675575