[BZOJ2227][Zjoi2011]看电影(movie)(组合数学+高精)
2018-02-19 20:10
302 查看
如果K<NK<N,则所有方案都是不行的,输出0101。
总方案数显然为KNKN。怎样构造一个合法方案呢?
考虑将第KK个座位和第11个座位连接起来,形成一个环,越过第KK个座位的人就回到第11个座位。那么合法方案就是不越过第KK个座位的方案数。
如何求不越过分界点的方案数呢?
再加一个座位,共K+1K+1个座位,同样把第KK个座位和第11个座位连接起来,形成一个环。这样分配的方案数是(K+1)N(K+1)N。由于是环,所以去除重复的方案,为(K+1)N−1(K+1)N−1。
可以看出,空的座位一定没有人越过。所以选一个空座位断开,形成一个序列,就构造成了一个合法方案。
一共有K+1−NK+1−N个空位,所以答案为:
(K+1)N−1(K+1−N)KN(K+1)N−1(K+1−N)KN
由于需要用到高精,要求最简分数,分子又是幂的形式,所以可以将K+1K+1,K+1−NK+1−N和KK分别分解质因数,这样就能较为方便地进行约分。
代码:
总方案数显然为KNKN。怎样构造一个合法方案呢?
考虑将第KK个座位和第11个座位连接起来,形成一个环,越过第KK个座位的人就回到第11个座位。那么合法方案就是不越过第KK个座位的方案数。
如何求不越过分界点的方案数呢?
再加一个座位,共K+1K+1个座位,同样把第KK个座位和第11个座位连接起来,形成一个环。这样分配的方案数是(K+1)N(K+1)N。由于是环,所以去除重复的方案,为(K+1)N−1(K+1)N−1。
可以看出,空的座位一定没有人越过。所以选一个空座位断开,形成一个序列,就构造成了一个合法方案。
一共有K+1−NK+1−N个空位,所以答案为:
(K+1)N−1(K+1−N)KN(K+1)N−1(K+1−N)KN
由于需要用到高精,要求最简分数,分子又是幂的形式,所以可以将K+1K+1,K+1−NK+1−N和KK分别分解质因数,这样就能较为方便地进行约分。
代码:
#include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; inline int read() { int res = 0; bool bo = 0; char c; while (((c = getchar()) < '0' || c > '9') && c != '-'); if (c == '-') bo = 1; else res = c - 48; while ((c = getchar()) >= '0' && c <= '9') res = (res << 3) + (res << 1) + (c - 48); return bo ? ~res + 1 : res; } typedef long long ll; const int N = 205, M = 6005, MX = 1e6; int n, K, cnt1 , cnt2 ; struct cyx { int n; ll a[M]; cyx() {} cyx(int _n, int val) : n(_n) {memset(a, 0, sizeof(a)); a[1] = val;} friend inline cyx operator * (cyx a, cyx b) { int i, j; cyx res = cyx(a.n + b.n + 2, 0); for (i = 1; i <= a.n; i++) for (j = 1; j <= b.n; j++) res.a[i + j - 1] += a.a[i] * b.a[j]; for (i = 1; i < res.n; i++) res.a[i + 1] += res.a[i] / MX, res.a[i] %= MX; while (res.n > 1 && !res.a[res.n]) res.n--; return res; } friend inline cyx operator ^ (cyx a, int b) { cyx res = cyx(1, 1); while (b) { if (b & 1) res = res * a; a = a * a; b >>= 1; } return res; } }; void pri(int a, int b, bool op) { int i, S = sqrt(a), tmp = a, *cnt = op ? cnt1 : cnt2; for (i = 2; i <= S; i++) while (tmp % i == 0) cnt[i] += b, tmp /= i; if (tmp > 1) cnt[tmp] += b; } void work() { memset(cnt1, 0, sizeof(cnt1)); memset(cnt2, 0, sizeof(cnt2)); int i; n = read(); K = read(); if (n > K) return (void) puts("0 1"); pri(K + 1, n - 1, 1); pri(K - n + 1, 1, 1); pri(K, n, 0); for (i = 1; i <= 200; i++) { int tmp = min(cnt1[i], cnt2[i]); cnt1[i] -= tmp; cnt2[i] -= tmp; } cyx r1 = cyx(1, 1), r2 = cyx(1, 1); for (i = 1; i <= 200; i++) r1 = r1 * (cyx(1, i) ^ cnt1[i]); for (i = 1; i <= 200; i++) r2 = r2 * (cyx(1, i) ^ cnt2[i]); printf("%d", r1.a[r1.n]); for (i = r1.n - 1; i; i--) printf("%06d", r1.a[i]); printf(" %d", r2.a[r2.n]); for (i = r2.n - 1; i; i--) printf("%06d", r2.a[i]); printf("\n"); } int main() { int i, j, T = read(); while (T--) work(); return 0; }
相关文章推荐
- [组合数学] BZOJ 2227 [Zjoi2011]看电影(movie)
- [BZOJ2227][Zjoi2011][找规律][排列组合][数学]看电影(movie)
- 【BZOJ2227】【ZJOI2011】看电影 [组合数][质因数分解]
- BZOJ2227 [Zjoi2011]看电影(movie)
- 2227: [Zjoi2011]看电影(movie)
- 2227: [Zjoi2011]看电影(movie)
- [BZOJ2111][ZJOI2010]Perm 排列计数(组合数学+lucas定理)
- BZOJ 2111 ZJOI2010 Perm 排列计数 组合数学+Lucas定理
- BZOJ2302: [HAOI2011]Problem c|动态规划|组合数学
- ZJOI2011 Day1 ( bzoj2227~2229 ) 题解
- BZOJ 2111: [ZJOI2010]Perm 排列计数|组合数学|Lucas定理|DP
- bzoj 2111: [ZJOI2010]Perm 排列计数 (组合数学+Lucas定理)
- BZOJ 2111 ZJOI2010 Perm 排列计数 组合数学+Lucas定理
- BZOJ 2111: [ZJOI2010]Perm 排列计数(简单组合数学)
- 【bzoj2339】【HNOI2011】【卡农】【组合数学+dp】
- [ZJOI2011]看电影(MOVIE)
- [BZOJ2111][ZJOI2010]Perm排列计数(组合数学)
- BZOJ 2339 HNOI2011 卡农 组合数学
- bzoj 2339: [HNOI2011]卡农 组合数学+递推
- [bzoj2111][ZJOI2010]Perm 排列计数(组合数学)