组合计数

不过对角线走格子问题

例1 : 给出一个 n*n 的网格图,问从格点 ( 0, 0 ) 走到 ( n, n ),不越过但可以接触到 y=x 这条直线的方案数。

答案即卡特兰数第n项。

卡特兰数普通递推公式: Ca(n,m)=Ca(n1,m)+Ca(n1,m1)

通项: Ca(n)=1n+1(2nn)

另类递推式 : Ca(n)=4n2n+1Ca(n1)

例2 : 给出一个 n*m 的网格图,问从格点 ( 0, 0 ) 走到 ( n, m ),不越过但可以接触到直线y=x的方案数。

首先把这条直线变成 y=x+1,那么就不可以接触到这条直线了。

然后通过总方案数减去沾到界限的方案数。

作个对称,使得从起点到终点的每一条路径必定经过这条直线。减去这些方案数就可以了。

为什么只能是直线 y=x 呢?

因为如果不是 y=x 的话,对称回来以后路径变“歪”了。画一下图很容易发现的。

例3 : ( JZOJ )骗我呢?

首先把DP转化为从一个平行四边形左上角走到右下角的方案数。

类似于例2的做法,做许多次对称,类似容斥原理地求解就可以了。

快速计算模任意数的卷积的分治算法

wikipedia上的介绍

这个算法的主要思想是把一个大整数分成两段计算,简化为每层递归做三次乘法运算,时间复杂度降为约 O( n1.585 )
结合伪代码可以更好地理解。

procedure karatsuba(num1, num2)
if (num1 < 10) or (num2 < 10)
return num1*num2
/* calculates the size of the numbers */
m = max(size_base10(num1), size_base10(num2))
m2 = m/2
/* split the digit sequences about the middle */
high1, low1 = split_at(num1, m2)
high2, low2 = split_at(num2, m2)
/* 3 calls made to numbers approximately half the size */
z0 = karatsuba(low1,low2)
z1 = karatsuba((low1+high1),(low2+high2))
z2 = karatsuba(high1,high2)
return (z2*10^(2*m2))+((z1-z2-z0)*10^(m2))+(z0)

补上一个可以在 O( n logn loglogn ) 时间复杂度内算卷积的Schönhage–Strassen算法

第一类斯特林数

wikipedia上的介绍
大致就是把n个东西分成m个环排列的方案数(也就是所有方案里每一组中的排列不可以通过环旋转变换达到)。
递推式: S(n,m)=S(n1,m)+(n1)S(n1,m1)
快速求法:
引理: xn=n1i=0(xi)=nk=1S(n,k)xk
然后问题就转化为了求递减阶乘多项式的系数
利用分治+FFT可以快速解决。

第二类斯特林数

wikipedia上的介绍在上一条链接中。
实际意义是把n个东西放到m个集合的方案数。
递推式: S(n,m)=S(n1,m1)+mS(n1,m)

你可能感兴趣的:(组合计数)