传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2822
这道题做得比较纠结,开始并没有看出什么,于是傻乎乎的写了个O(n^3)的dp,设f[i][j]表示前i行,第i行有j条竖线的方案数,
则f[i][j] = sigma(f[i - 1][k]) (j - 1 <= k < i - 1)
经打表发现这其实是卡特兰数列,吓傻了⊙﹏⊙b汗
其实我们可以发现,只需要枚举一个分割的矩形,就可以把原图分为两个部分,设f[i]表示有i行的方案数,则f[i] = sigma(f[k] * f[i - k - 1]) (0 <= k < i)
这就是卡特兰数列,而为了防止超时,将式子变形为:f[i] = f[i - 1] * (4 * i - 2) / (i + 1);
复杂度为O(n) * 高精度
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int maxn = 510; struct node { int a[maxn]; node() { memset(a, 0, sizeof(a)); a[0] = 1; } void operator *= (int t) { for(int i = 1; i <= a[0]; i ++) { a[i] *= t; } for(int i = 1; i <= a[0]; i ++) { a[i + 1] += a[i] / 10; a[i] %= 10; } int k = a[0] + 1; while(a[k]) { a[k + 1] += a[k] / 10; a[k] %= 10; k ++; } k --; a[0] = k; } node operator / (int t) { node tt; int res = 0; for(int i = a[0]; i ; i --) { res = res * 10 + a[i]; tt.a[i] = res / t; res %= t; } int k = a[0]; while(k > 1 && !tt.a[k]) k --; tt.a[0] = k; return tt; } void print() { for(int i = a[0]; i ; i --) { printf("%d", a[i]); } printf("\n"); } }f[maxn]; int n; int main() { scanf("%d", &n); f[0].a[1] = f[1].a[1] = 1; for(int i = 2; i <= n; i ++) { f[i] = f[i - 1]; int t1 = 4 * i - 2, t2 = i + 1; f[i] *= t1; f[i] = f[i] / t2; } f[n].print(); return 0; }