BZOJ1485
-
题目
-
分析
可以找规律发现是 C a t l a n Catlan Catlan 数列。。
还是证明一下:
性质2: a 1 < a 3 < . . < a 2 i − 1 a_1 < a_3 < ..<a_{2i-1} a1<a3<..<a2i−1 , a 2 < a 4 < . . . < a 2 i a_2<a_4<...<a_{2i} a2<a4<...<a2i
a 1 < a 3 < . . . a 2 i − 1 < a 2 i 可 以 得 出 在 偶 数 位 上 的 数 比 它 左 边 所 有 数 都 要 大 , 换 句 话 说 偶 数 位 上 的 数 大 于 等 于 这 个 偶 数 位 的 下 标 。 由 性 质 2 从 小 到 大 放 数 字 的 时 候 要 尽 量 靠 左 放 假 设 已 经 放 了 1 ∼ x 个 数 , x 1 个 放 在 奇 数 位 上 , x 2 个 放 在 偶 数 位 上 , 则 x 2 < x 1 . 证 明 一 下 : 假 设 x 2 > x 1 , x 2 > x 2 , 由 偶 数 位 上 的 数 大 于 等 于 这 个 偶 数 位 的 下 标 , 最 后 一 个 偶 数 位 下 标 应 该 是 2 × x 2 2 × x 2 > x , 而 只 有 x 个 数 , 所 以 假 设 不 成 立 。 \begin{aligned} & a_1 < a_3 < ... a_{2i-1} < a_{2i} \\ & 可以得出在偶数位上的数比它左边所有数都要大,换句话说偶数位上的数大于等于这个偶数位的下标。\\ & 由性质2从小到大放数字的时候要尽量靠左放 \\ & 假设已经放了1 \sim x 个数,x_1个放在奇数位上,x_2个放在偶数位上,则x_2 < x_1. \\ & 证明一下:\\ & 假设x_2 > x_1, x_2 > \frac{x}{2},由偶数位上的数大于等于这个偶数位的下标,最后一个偶数位下标应该是 2 \times x_2 \\ & 2 \times x_2 > x,而只有x个数,所以假设不成立。 \end{aligned} a1<a3<...a2i−1<a2i可以得出在偶数位上的数比它左边所有数都要大,换句话说偶数位上的数大于等于这个偶数位的下标。由性质2从小到大放数字的时候要尽量靠左放假设已经放了1∼x个数,x1个放在奇数位上,x2个放在偶数位上,则x2<x1.证明一下:假设x2>x1,x2>2x,由偶数位上的数大于等于这个偶数位的下标,最后一个偶数位下标应该是2×x22×x2>x,而只有x个数,所以假设不成立。
所以得出结论:按从小到大的顺序放到任意一个数 x x x ,都满足放在偶数位上的数字个数小于等于放在奇数位上的数字个数 .这很明显是 C a t l a n Catlan Catlan 数。。。
本题实现还是有点意思。。
J a v a Java Java 大数超时可能太卡了吧。。。 J a v a Java Java 不知道开了多少时间。。
C a t l a n Catlan Catlan 数列通项公式用: C 2 n n ( n + 1 ) ! \displaystyle\frac{C_{2n}^{n}}{(n+1)!} (n+1)!C2nn 化简: ∏ i = n + 2 2 n i n ! \displaystyle\frac{\prod_{i = n+2}^{2n}i}{n!} n!∏i=n+22ni
模数居然不是质数。。。不好求逆元
运用智慧对分子用唯一分解,分成 p 1 c 1 p 2 c 2 . . . p m c m p_1^{c_1}p_2^{c_2}...p_m^{c_m} p1c1p2c2...pmcm ,分母: p 1 b 1 p 2 b 2 . . . . p m b m p_1^{b_1}p_2^{b_2}....p_m^{b_m} p1b1p2b2....pmbm
除的话就是: p 1 c 1 − b 1 p 2 c 2 − b 2 . . . p m c m − b m p_1^{c_1-b_1}p_2^{c_2-b_2}...p_m^{c_m-b_m} p1c1−b1p2c2−b2...pmcm−bm , k s m ksm ksm 一下,就可以了。。注意分解的时候要预处理出 1 ∼ 2 n 1\sim 2n 1∼2n 的质数会快很多。。别傻乎乎的直接算。。
说的就是我 -
代码
const int N = 2e6 + 6; int v[N], prime[N]; int m; int c[N]; void primes(int n) { memset(v, 0, sizeof(v)); m = 0; for (int i = 2; i <= n; i++) { if (v[i] == 0) { v[i] = i; prime[++m] = i; } for (int j = 1; j <= m; j++) { if (prime[j] > v[i] || prime[j] > n / i) break; v[i * prime[j]] = prime[j]; } } } void divid(int x, int d) { for (int i = 1; i <= m && prime[i] * prime[i] <= x; i++) { if (x % prime[i] == 0) { while (x % prime[i] == 0) { c[prime[i]] += d; x /= prime[i]; } } } if (x > 1) c[x] += d; } ll ksm(ll a, ll b, ll mod) { ll ans = 1 % mod; while (b > 0) { if (b & 1) ans = ans * a % mod; b >>= 1; a = a * a % mod; } return ans % mod; } int main() { int n, p; read(n); read(p); primes(n << 1); for (int i = n + 2; i <= (n << 1); i++) divid(i, 1); // 处理分子 for (int i = 1; i <= n; i++) divid(i, -1); // 处理分母 ll ans = 1; for (int i = 1; i <= m; i++) { if (c[prime[i]]) { ans = ans * ksm(prime[i], c[prime[i]], p); //累乘 ans %= p; } } cout << ans << endl; return 0 ; }
-
题型
C a t l a n Catlan Catlan数