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;
}

浙公网安备 33010602011771号