CF896D Nephren Runs a Cinema

看了番,速来补题。(Nephren 没死,可以说是万幸了。)
虽然不知道为什么有黑?感觉是扩展Lucas板子?

题相当于是计数一个ABC序列,使得序列长度为\(n\),且对于每一个前缀,A的数量大于B的数量。A的总数减B的总数在\([l,r]\)内。
那么我们可以枚举\(C\)的数量,然后接下来就是一堆很典的格路计数。总之现在我们只用计算\(O(n)\)\(\binom{x}{y}\bmod P\)\(x\le 1e5,y\le 1e5,P\le 2e9\)
然后我们上扩展lucas板子,不过稍微变一下形式。
CRT后,将\(\binom{n}{m}\bmod P^k\)直接拆成\(\Large \frac{\frac{n!}{P^x}}{\frac{m!}{P^y}\frac{(n-m)!}{P^z}} P^{x-y-z}\bmod P^k\),其中\(\frac{n!}{P^x}\)表示为\(n!\)除去所有\(P\)因子的值
计算\(\large f(n)=\frac{n!}{P^x}\)时,
因为\(f(n)=f(\lfloor \frac{n}{P}\rfloor )\prod_{i=1,i\nmid P}^{n}i \bmod P^k\),我们可以预处理出\(\prod_{i=1,i\nmid P}^{n}i \bmod P^k\)
这样时间就是显然的\(O(n\log^2 n)\)了。
原神代码:

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=2e5+5,M=1005;
int P,Pk;
bool vis[N];
int prime[N],pcnt;
inline ll ksm(ll a,ll b,ll p){
	ll res=1;
	while(b){
		if(b&1)res=res*a%p;
		a=a*a%p,b>>=1;
	}
	return res;
}
void prew(){
	for(int i=2;i<N;i++){
		if(!vis[i]){
			vis[i]=1;
			prime[++pcnt]=i;
		}
		for(int j=1;i*prime[j]<N&&j<=pcnt;j++){
			int x=i*prime[j];
			vis[x]=1;
			if(i%prime[j]==0)continue;
		}
	}
}
void exgcd(ll a,ll b,ll &x,ll &y){
	if(!b)return x=1,y=0,void();
	exgcd(b,a%b,y,x);
	y-=a/b*x;
}
inline ll ginv(ll a,ll ps){
	a%=ps;
	ll x,y;
	exgcd(a,ps,x,y);
	return (x%ps+ps)%ps;
}
ll fac[24][N];
int cnt;
int s1[N],s2[N];
int cur;
ll res[N];
inline int g(int x){
	if(!x)return 0;
	return x/P+g(x/P);
}
inline ll f(int x){
	if(x==0)return 1;
	return f(x/P)*fac[cur][x]%Pk;
}
inline ll solve(int n,int m){
	return ksm(P,g(n)-g(m)-g(n-m),Pk)*f(n)%Pk*ginv(f(n-m),Pk)%Pk*ginv(f(m),Pk)%Pk;
}
int p;
inline ll C(int n,int m){
	if(m<0||n<m)return 0;
	for(int i=1;i<=cnt;i++){
		cur=i;P=s1[i],Pk=s2[i];
		res[i]=solve(n,m);
	}
	ll ans=0;
	for(int i=1;i<=cnt;i++){
		Pk=s2[i];
		ans+=1ll*res[i]*(p/Pk)%p*ginv(p/Pk,Pk)%p;
	}
	return ans%p;
}
int n,l,r;
int main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	prew();
	cin>>n>>p>>l>>r;
	int kp=p;
	for(int i=1;i<=pcnt;i++){
		int x=prime[i];
		if(kp%x==0){
			++cnt;
			s1[cnt]=x,s2[cnt]=x,kp/=x;
			while(kp%x==0)kp/=x,s2[cnt]*=x;
		}
		if(kp==1)break;
	}
	if(kp^1){
		++cnt;
		s1[cnt]=kp,s2[cnt]=kp;
	}
	for(int i=1;i<=cnt;i++){
		fac[i][0]=1;
		for(int j=1;j<=n;j++){
			if(j%s1[i])fac[i][j]=fac[i][j-1]*j%s2[i];
			else fac[i][j]=fac[i][j-1];
		}
	}
	ll ans=0;
	for(int i=0;i<=n;i++){
		int pl=(i+l+1)/2,pr=(i+r)/2;
		pl=max(pl,0),pr=min(pr,i);
		pl=max(pl,(i+1)/2);
		if(pl>pr)continue;
		ll res=0;
		res+=C(i,pl)-C(i,pr+1)+p;
		res%=p;
		ans+=res*C(n,i)%p;
	}
	cout<<ans%p<<"\n";
	return 0;
}
posted @ 2025-04-09 20:49  wjwweiwei  阅读(11)  评论(0)    收藏  举报