洛谷 P4478 [BJWC2018]上学路线

洛谷 P4478 [BJWC2018]上学路线


原题

神仙题orz,竟然没有1A。。。。容斥+卢卡斯+crt??

首先用容斥做,记\(f[i][0/1]\)表示到i号点经过了奇数/偶数个点的方案数,因为\(f[i][0]+f[i][1]=1\)所以只要记一个\(f[i]\)是经过奇数个点的方案数就行

枚举一个左下的点走到这个点,或者直接从1走到这个点,

\(f[i]=\sum_{\text{j in lower left side}}((1-f[j])\times C_{x_i+y_i-x_j-y_j}^{x_i-x_j})+C_{x_i+y_i}^{x_i}\)

答案就是从所有点走到这个点,加上从1号点走到这个点\(\sum_{i}((1-f[i])\times C_{n+m-x_i-x_j}^{n-x_i})+C_{n+m}^{n}\)

sort一遍dp就做完了,只剩下求组合数了

模数好像不是质数,分解一下发现是3×5×6793×10007

crt即可,对每个模数求一遍方案,求组合数用lucas

lucas大概就是\(C_{n}^{m}\text{mod }p=C_{\lfloor\frac{n}{p}\rfloor}^{{\lfloor\frac{m}{p}\rfloor}}\times C_{n\text{ mod }p}^{m\text{ mod }p}\mod p\)

这神仙题就做完了。。。

#include<bits/stdc++.h>
#define il inline
#define vd void
typedef long long ll;
il ll gi(){
	ll x=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
	return x;
}
ll mod;
struct yyb{ll x,y;}a[210];
il bool cmp(const yyb&a,const yyb&b){
	if(a.x^b.x)return a.x<b.x;
	return a.y<b.y;
}
ll f[210];
ll p[5],tot;
ll Ans[5];
ll pp[5],tt[5];
ll fact[1000010],inv[1000010];
il ll C(ll n,ll m,ll P){
	if(n<m)return 0;
	return fact[n]*inv[fact[m]*fact[n-m]%P]%P;
}
il ll Lucas(ll n,ll m,ll P){
	if(n<m)return 0;if(!n)return 1;
	return Lucas(n/P,m/P,P)*C(n%P,m%P,P)%P;
}
int main(){
#ifndef ONLINE_JUDGE
	freopen("4478.in","r",stdin);
	freopen("4478.out","w",stdout);
#endif
	ll n=gi(),m=gi(),t=gi();mod=gi();
	if(mod==1000003)p[tot=1]=mod;
	else p[++tot]=3,p[++tot]=5,p[++tot]=6793,p[++tot]=10007;
	for(int i=1;i<=t;++i)a[i].x=gi(),a[i].y=gi();
	std::sort(a+1,a+t+1,cmp);
	ll M=1;
	for(int i=1;i<=tot;++i)M*=p[i];
	for(int i=1;i<=tot;++i)pp[i]=M/p[i];
	for(int o=1;o<=tot;++o){
		ll P=p[o];
		inv[1]=1;for(int i=2;i<P;++i)inv[i]=(P-(P/i)*inv[P%i]%P)%P;
		tt[o]=inv[pp[o]%P];
		fact[0]=1;for(int i=1;i<P;++i)fact[i]=fact[i-1]*i%P;
		Ans[o]=Lucas(n+m,n,P);
		for(int i=1;i<=t;++i){
			f[i]=Lucas(a[i].x+a[i].y,a[i].x,P);
			for(int j=1;j<i;++j)
				if(a[j].x<=a[i].x&&a[j].y<=a[i].y)
					f[i]+=P-f[j]*Lucas(a[i].x+a[i].y-a[j].x-a[j].y,a[i].x-a[j].x,P)%P;
			f[i]%=P;
			Ans[o]+=P-Lucas(n+m-a[i].x-a[i].y,n-a[i].x,P)*f[i]%P;
		}
		Ans[o]%=P;
	}
	ll ans=0;
	for(int i=1;i<=tot;++i)ans+=Ans[i]*pp[i]%mod*tt[i]%mod;
	printf("%lld\n",ans%mod);
	return 0;
}
posted @ 2018-10-02 15:26  菜狗xzz  阅读(313)  评论(0编辑  收藏  举报