[ZJOI2010] 정렬 개수

1352 단어
좋은 문제, 실제가 무더기의 종수라는 것을 알아차리고 조합수를 잊어버렸다.
/**

 * 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;

}


좋은 웹페이지 즐겨찾기