【bzoj3782】上学路线 dp+容斥原理+Lucas定理+中国剩余定理

题目描述

小C所在的城市的道路构成了一个方形网格,它的西南角为(0,0),东北角为(N,M)。小C家住在西南角,学校在东北角。现在有T个路口进行施工,小C不能通过这些路口。小C喜欢走最短的路径到达目的地,因此他每天上学时都只会向东或北行走;而小C又喜欢走不同的路径,因此他问你按照他走最短路径的规则,他可以选择的不同的上学路线有多少条。由于答案可能很大,所以小C只需要让你求出路径数mod P的值。

输入

第一行,四个整数N、M、T、P。

接下来的T行,每行两个整数,表示施工的路口的坐标。

输出

一行,一个整数,路径数mod P的值。

样例输入

3 4 3 1019663265
3 0
1 1
2 2

样例输出

8

提示

p=1000003 或 p=1019663265



题解

dp+Lucas定理+中国剩余定理

设$f[i]$表示从$(0,0)$走到第i个坏点(终点算作第T+1个坏点),中途不经过其它坏点的方案数。

那么直接求$f[i]$比较困难,考虑单步容斥,用总方案数-经过坏点的方案数推出$f[i]$。

从$(0,0)$走到$(n,m)$的总方案数为$C_{n+m}^n$,可以看做总共n+m步,其中n步是x方向。

而经过坏点的方案数,枚举其经过的第一个坏点,那么它的贡献为|从$(0,0)走到该点,中途不经过其它坏点的方案数|*|从这个坏点走到当前点的方案数|。

第一个即为坏点的$f$值,第二个用组合数求法求出。

最后的答案就是$f[T+1]$。

然而本题较为恶心之处在于模数,当p=1000003时可以直接使用Lucas定理,而当p=1019663265时p不为质数,将其分解质因数为3*5*6793*10007,使用Lucas定理分别求出组合数在模这些质因子意义下的值,再使用中国剩余定理CRT合并,才能得到组合数模1019663265的值。

细节还是有点多,代码已经差不多优化到极限了,凑合着看吧。。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll mod[] = {1000003 , 3 , 5 , 6793 , 10007} , temp = 1019663265;
struct data
{
	ll x , y;
	bool operator<(const data a)const {return x == a.x ? y < a.y : x < a.x;}
}a[210];
ll f[210] , fac[5][1000010] , d[5];
bool flag;
ll pow(ll x , ll y , ll p)
{
	ll ans = 1;
	while(y)
	{
		if(y & 1) ans = ans * x % p;
		x = x * x % p , y >>= 1;
	}
	return ans;
}
ll choose(ll n , ll m , ll p)
{
	if(n < m) return 0;
	if(n < mod[p] && m < mod[p]) return fac[p][n] * pow(fac[p][m] , mod[p] - 2 , mod[p]) % mod[p] * pow(fac[p][n - m] , mod[p] - 2 , mod[p]) % mod[p];
	return choose(n / mod[p] , m / mod[p] , p) * choose(n % mod[p] , m % mod[p] , p) % mod[p];
}
ll C(ll n , ll m)
{
	if(!flag) return choose(n , m , 0);
	int i;
	ll ans = 0;
	for(i = 1 ; i < 5 ; i ++ ) d[i] = choose(n , m , i);
	for(i = 1 ; i < 5 ; i ++ ) ans = (ans + temp / mod[i] * pow(temp / mod[i] , mod[i] - 2 , mod[i]) % temp * d[i] % temp) % temp;
	return ans;
}
int main()
{
	ll n , m;
	int p , T , i , j;
	scanf("%lld%lld%d%d" , &n , &m , &T , &p) , flag = (p != 1000003);
	for(i = 0 ; i < 5 ; i ++ )
		for(fac[i][0] = j = 1 ; j < mod[i] ; j ++ )
			fac[i][j] = fac[i][j - 1] * j % mod[i];
	for(i = 1 ; i <= T ; i ++ ) scanf("%lld%lld" , &a[i].x , &a[i].y);
	a[++T].x = n , a[T].y = m;
	sort(a + 1 , a + T + 1);
	for(i = 1 ; i <= T ; i ++ )
	{
		f[i] = C(a[i].x + a[i].y , a[i].x);
		for(j = 1 ; j < i ; j ++ )
			if(a[j].y <= a[i].y)
				f[i] = (f[i] - f[j] * C(a[i].y - a[j].y + a[i].x - a[j].x , a[i].y - a[j].y) % p + p) % p;
	}
	printf("%lld\n" , f[T]);
	return 0;
}
时间: 2024-10-25 08:35:17

【bzoj3782】上学路线 dp+容斥原理+Lucas定理+中国剩余定理的相关文章

BZOJ-1951-古代猪文-SDOI2010-费马小定理+欧拉函数+lucas定理+中国剩余定理

描述 =>G∑(ni),i|nmodP 分析 k=∑Cin,i|n(modP) G?(P)≡1(modP),?(p)=p?1 P′=P?1 =>GP′≡1(modP) Gk≡GkmodP′(modP) 如何求k? lucas定理 (nm)=(nmodP′mmodP′)?(n/P′m/P′) P'不是素数, lucas定理不适用. 所以把P'-1拆成2*3*4679*35617再用中国剩余定理来解. 一下子用这么多不熟悉的定理和方法感觉这个题好厉害. 终于知道当被模的数不是质数该怎么用中国剩余定

hdu 5446 Unknown Treasure Lucas定理+中国剩余定理

Unknown Treasure Time Limit: 1500/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 2209    Accepted Submission(s): 821 Problem Description On the way to the next secret treasure hiding place, the mathematician

数论E - Biorhythms(中国剩余定理,一水)

E - Biorhythms Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submit Status Description Some people believe that there are three cycles in a person's life that start the day he or she is born. These three cycles are the

gcd,扩展欧几里得,中国剩余定理

1.gcd: int gcd(int a,int b){ return b==0?a:gcd(b,a%b); } 2.中国剩余定理: 题目:学生A依次给n个整数a[],学生B相应给n个正整数m[]且两两互素,老师提出问题:有一正整数ans,对于每一对数,都有:(ans-a[i])mod m[i]=0.求此数最小为多少. 输入样例: 1 10 2 3 1 2 3 2 3 5 8 1 2 3 4 5 6 7 8 97 89 67 61 59 53 47 88 12 1 2 3 4 5 6 7 8 9

HDU 1573 X问题 中国剩余定理

链接:http://acm.hdu.edu.cn/showproblem.php?pid=1573 题意:求在小于等于N的正整数中有多少个X满足:X mod a[0] = b[0], X mod a[1] = b[1], X mod a[2] = b[2], -, X mod a[i] = b[i], - (0 < a[i] <= 10). 思路:中国剩余定理的模板题,如果找不到这样的数或者最小的X大于N,输出零. 代码: #include <iostream> #include

同余 模算术 中国剩余定理

相关知识点: 1.a≡b(modc),a,b关于模c同余  ,即a modc=b mod c , 等价于a%c=b 2.如果a,b互质(a,b)=1,则可得a关于模b的逆 ax≡1(modb) 3.关于余数的定理: 定理1 :如果被除数加上(或减去)除数的整数倍,除数不变,则余数不变. 定理2 :如果被除数扩大(或缩小)几倍,除数不变,则余数也扩大(或缩小)同样的倍数. 定理3: 如果整数a除以自然数b(b≠0),余数r仍不小于b,则r除以b的余数等于a除以b所得余数.(余数和被除数关于除数同余

hihocode 九十七周 中国剩余定理

题目1 : 数论六·模线性方程组 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Ho:今天我听到一个挺有意思的故事! 小Hi:什么故事啊? 小Ho:说秦末,刘邦的将军韩信带领1500名士兵经历了一场战斗,战死四百余人.韩信为了清点人数让士兵站成三人一排,多出来两人:站成五人一排,多出来四人:站成七人一排,多出来六人.韩信立刻就知道了剩余人数为1049人. 小Hi:韩信点兵嘛,这个故事很有名的. 小Ho:我觉得这里面一定有什么巧妙的计算方法!不然韩信不可能这么快计

POJ 1006 中国剩余定理

[题意]: 给定p,e,i,d,求解 (x + d) % 23 = p (x + d) % 28 = e(x + d) % 33 = i x最小正整数值 [知识点]: 中国剩余定理 [题解]: 典型的 xmodmi = ai模型,其中mi间两两互素.但该题式子较少,也可以直接自己化简带入值. [代码]: 1 #include <map> 2 #include <set> 3 #include <cmath> 4 #include <ctime> 5 #inc

转载----POJ 1006 中国剩余定理

本文为转载,源地址:   http://blog.csdn.net/dongfengkuayue/article/details/6461298 POJ 1006   Biorhythms Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 78980   Accepted: 23740 Description Some people believe that there are three cycles in a perso