bzoj5329 上学路线(dp+容斥+组合数学+Lucas+CRT)

把终点也视为一个坏点的话,f[i]表示到达坏点i且不经过其他坏点的方案数。直接计算f[i]比较困难,考虑容斥。
可以通过组合数学方便的得到从一个点到另一个点的总方案数。那么我们可以再枚举经过的第一个坏点来减去不合法的方案。
这里算组合数需要Lucas定理,1019663265=3*5*6793*10007不是质数,但好在次数都是1,我们对每一个质因子算一下再CRT合并起来即可。
复杂度 O ( n 2 l o g P )

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 210
inline ll read(){
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int P[5]={1000003,3,5,6793,10007},f[N],Mod,inv[5][1000010],fac[5][1000010];
struct point{
    ll x,y;
    friend bool operator<(point a,point b){return a.x==b.x?a.y<b.y:a.x<b.x;}
}a[N];
inline void inc(int &x,int y){x+=y;x%=Mod;}
inline int ksm(int x,int k,int mod){
    int res=1;for(;k;k>>=1,x=(ll)x*x%mod) if(k&1) res=(ll)res*x%mod;return res;
}
inline ll C(int n,int m,int i){
    if(m>n) return 0;return (ll)fac[i][n]*inv[i][m]%P[i]*inv[i][n-m]%P[i];
}
inline int lucas(ll n,ll m,int i){
    int res=1;
    for(;m;n/=P[i],m/=P[i]) res=(ll)res*C(n%P[i],m%P[i],i)%P[i];
    return res;
}
inline int calc(ll n,ll m){
    if(Mod==P[0]) return lucas(n,m,0);int M=1019663265;int res=0;
    for(int i=1;i<=4;++i) inc(res,(ll)M/P[i]*ksm(M/P[i],P[i]-2,P[i])*lucas(n,m,i)%M);return res;
}
inline void init(int id){
    int mod=P[id];int *a=fac[id],*b=inv[id];
    a[0]=1;b[0]=1;b[1]=1;
    for(int i=2;i<mod;++i) b[i]=(ll)b[mod%i]*(mod-mod/i)%mod;
    for(int i=1;i<mod;++i) a[i]=(ll)a[i-1]*i%mod,b[i]=(ll)b[i-1]*b[i]%mod;
}
int main(){
//  freopen("a.in","r",stdin);
    ll tx=read(),ty=read();int n=read();Mod=read();
    if(Mod==P[0]) init(0);
    else for(int i=1;i<=4;++i) init(i);
    for(int i=1;i<=n;++i) a[i].x=read(),a[i].y=read();a[++n].x=tx;a[n].y=ty;sort(a+1,a+n+1);
    for(int i=1;i<=n;++i){
        f[i]=calc(a[i].x+a[i].y,a[i].x);
        for(int j=1;j<i;++j){
            if(a[j].y>a[i].y) continue;
            inc(f[i],(ll)f[j]*calc(a[i].x-a[j].x+a[i].y-a[j].y,a[i].x-a[j].x)%Mod*(Mod-1)%Mod);
        }
    }printf("%d\n",f[n]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/icefox_zhx/article/details/80535735
今日推荐