不过对角线走格子问题
例1 : 给出一个 n*n 的网格图,问从格点 ( 0, 0 ) 走到 ( n, n ),不越过但可以接触到 y=x 这条直线的方案数。
答案即卡特兰数第n项。
卡特兰数普通递推公式: Ca(n,m)=Ca(n−1,m)+Ca(n−1,m−1)
通项: Ca(n)=1n+1(2nn)
另类递推式 : Ca(n)=4n−2n+1Ca(n−1)
例2 : 给出一个 n*m 的网格图,问从格点 ( 0, 0 ) 走到 ( n, m ),不越过但可以接触到直线y=x的方案数。
首先把这条直线变成 y=x+1,那么就不可以接触到这条直线了。
然后通过总方案数减去沾到界限的方案数。
作个对称,使得从起点到终点的每一条路径必定经过这条直线。减去这些方案数就可以了。
为什么只能是直线 y=x 呢?
因为如果不是 y=x 的话,对称回来以后路径变“歪”了。画一下图很容易发现的。
例3 : ( JZOJ )骗我呢?
首先把DP转化为从一个平行四边形左上角走到右下角的方案数。
类似于例2的做法,做许多次对称,类似容斥原理地求解就可以了。
快速计算模任意数的卷积的分治算法
这个算法的主要思想是把一个大整数分成两段计算,简化为每层递归做三次乘法运算,时间复杂度降为约 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(n−1,m)+(n−1)S(n−1,m−1)
快速求法:
引理:
xn−=∏n−1i=0(x−i)=∑nk=1S(n,k)xk
然后问题就转化为了求递减阶乘多项式的系数
利用分治+FFT可以快速解决。
第二类斯特林数
wikipedia上的介绍在上一条链接中。
实际意义是把n个东西放到m个集合的方案数。
递推式:
S(n,m)=S(n−1,m−1)+mS(n−1,m)