[ZJOI2010]排列计数

好题,看出来实际是个堆的种数,忘了组合数。。

/**
 * Problem:Magic
 * Author:Shun Yao
 * Time:2013.6.2
 * Result:Accepted
 * Memo:DP, Math
 */

#include <cstdio>
#include <cmath>

const long Maxn = 1000005;

long min(long x, long y) {
	return x < y ? x : y;
}

long n;
long long p, f[Maxn], d[Maxn], jc[Maxn];

void exgcd(long long a, long long b, long long &x, long long &y) {
	if (!b) {
		x = 1;
		y = 0;
	} else {
		exgcd(b, a % b, y, x);
		y -= a / b * x;
	}
}

long long mulinv(long long X) {
	long long x, y;
	exgcd(X, p, x, y);
	return ((-x) / p * p + x + p) % p;
}

int main() {
	long i, dep, u, l, r;
	freopen("magic.in", "r", stdin);
	freopen("magic.out", "w", stdout);
	scanf("%ld%lld", &n, &p);
	jc[0] = 1;
	for (i = 1; i <= n; ++i)
		jc[i] = jc[i - 1] * i % p;
	f[0] = f[1] = d[0] = d[1] = 1 % p;
	for (i = 2; i <= n; ++i) {
		dep = (long)(log(i) / log(2) + 1e-10);
		u = (long)(pow(2.0, dep) + 1e-10) - 1;
		l = ((u - 1) >> 1) + min(i - u, ((u + 1) >> 1));
		r = i - 1 - l;
		f[i] = f[l] * f[r] % p * jc[i - 1] % p;
		d[i] = d[l] * d[r] % p * jc[l] % p * jc[r] % p;
	}
	printf("%lld", f[n] * mulinv(d[n]) % p);
	fclose(stdin);
	fclose(stdout);
	return 0;
}

 

posted @ 2013-06-03 15:22  hsuppr  阅读(164)  评论(0编辑  收藏  举报