BZOJ 2111 / Luogu P2606 [ZJOI2010]排列计数

21 篇文章 0 订阅
10 篇文章 1 订阅

题意

称一个 1 , 2 , . . . , N 1,2,...,N 1,2,...,N的排列 P 1 , P 2 . . . , P n P_1,P_2...,P_n P1,P2...,Pn M a g i c Magic Magic的,当且仅当 2 < = i < = N 2<=i<=N 2<=i<=N时, P i > P i / 2 P_i>P_{i/2} Pi>Pi/2. 计算 1 , 2 , . . . N 1,2,...N 1,2,...N的排列中有多少是 M a g i c Magic Magic的,答案可能很大,只能输出模 P P P以后的值。

题解

这道题最妙的就是把题目转化为求 n n n个点的小根堆数量。

然后就随便DP了。

注意模数可能小于 N N N,要用 l u c a s lucas lucas定理。

CODE

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 2000005;

int fac[MAXN], inv[MAXN], mod, n, sz[MAXN];

inline int C(int x, int y) {
	if(x < y) return 0;
	if(x < mod && y < mod) return 1ll * fac[x] * inv[y] % mod * inv[x-y] % mod;
	return 1ll * C(x%mod, y%mod) * C(x/mod, y/mod) % mod;
}

void dfs1(int i) {
	if(i > n) return;
	sz[i] = 1;
	dfs1(i<<1); sz[i] += sz[i<<1];
	dfs1(i<<1|1); sz[i] += sz[i<<1|1];
}

int dfs2(int i) {
	if(i > n) return 1;
	int re = C(sz[i]-1, sz[i<<1]);
	re = 1ll * re * dfs2(i<<1) % mod;
	re = 1ll * re * dfs2(i<<1|1) % mod;
	return re;
}

int main ()
{
	scanf("%d%d", &n, &mod);
	fac[0] = inv[0] = fac[1] = inv[1] = 1;
	for(int i = 2; i <= n; ++i) inv[i] = 1ll * (mod - mod/i) * inv[mod%i] % mod;
	for(int i = 2; i <= n; ++i) fac[i] = 1ll * fac[i-1] * i % mod, inv[i] = 1ll * inv[i] * inv[i-1] % mod;
	dfs1(1);
	printf("%d\n", dfs2(1));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值