首页 > 其他分享 >P2606 [ZJOI2010] 排列计数 题解

P2606 [ZJOI2010] 排列计数 题解

时间:2024-02-29 15:55:20浏览次数:22  
标签:return invfac int 题解 ZJOI2010 P2606 MAXN dp mod

题意:求有多少个排列满足:对于每一个 \(2 \le i \le n\),\(a_i > a_{\frac{i}{2}}\)。

首先我们会发现这些数之间的大小关系形成了一个完全二叉树,因为每一个 \(a_i\) 都必须小于 \(a_{2\times i}\) 和 \(a_{2 \times i + 1}\)。

会发现本题的方案和每个位置具体的值并没有关系,而只在乎两个位置之间的大小关系。

那么我们设 \(dp_i\) 表示在大小为 \(i\) 的完全二叉树内放 \(i\) 个不同的数的方案数(注意这里只考虑两数之间的大小关系,而不考虑每个数具体的值)。根节点只能放最小的数,假设根节点的左子树有 \(L\) 个点,右子树有 \(R\) 个点。在剩下的 \(i-1\) 个数中,可以选 \(L\) 个放到左子树中,有 \(C_{i-1}^{L}\) 种选法,其余的放到右子树。所以有:

\[dp_i=C_{i-1}^{L} \times dp_L \times dp_{R} \]

因为 \(n,m\) 有可能大于 \(mod\),所以需要用 \(\text{Lucas}\) 定理来计算组合数,时间复杂度 \(O(n \log n)\)。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN = 1e6 + 10;
int n,mod,dp[MAXN],inv[MAXN],fac[MAXN],invfac[MAXN];
inline int C(int n,int m)
{
	if(n < m || m < 0) return 0;
	return fac[n] * invfac[m] % mod * invfac[n - m] % mod;
}
inline int Lucas(int n,int m)
{
	if(n < mod && m < mod) return C(n,m);
	return Lucas(n / mod,m / mod) * C(n % mod,m % mod) % mod;
}
signed main()
{
	cin >> n >> mod;
	inv[0] = fac[0] = invfac[0] = 1;
	inv[1] = fac[1] = invfac[1] = 1;
	for(int i = 2;i <= min(n,mod - 1);i++)
	{
		fac[i] = fac[i - 1] * i % mod;
		inv[i] = inv[mod % i] * (mod - mod / i) % mod;
		invfac[i] = invfac[i - 1] * inv[i] % mod;
	}
	dp[1] = dp[0] = 1;
	for(int i = 2;i <= n;i++)
	{
		int L = (1 << (__lg(i) - 1)) - 1,R = (1 << (__lg(i) - 1)) - 1;
		if((i - L - R - 1) <= (1 << (__lg(i) - 1))) L += (i - L - R - 1);
		else L += (1 << (__lg(i) - 1)),R = i - L - 1;
		dp[i] = Lucas(i - 1,L) * dp[L] % mod * dp[R] % mod;
 	}
	cout << dp[n];
 	return 0;
}

标签:return,invfac,int,题解,ZJOI2010,P2606,MAXN,dp,mod
From: https://www.cnblogs.com/Creeperl/p/18044469

相关文章

  • 打击犯罪(题解)
    题目题目描述样例输入722531342242233167257256样例输出1关于本题这个题反着想会很简单,也就是复活犯罪,但是这个反着的思路不好想到(比如我就没想到)。看其他blog基本上都是反着来的,确实复杂度小不少,但是别人写过的我就不写了,我就给出正着来的解......
  • [ABC282Ex] Min + Sum 题解
    [ABC282Ex]Min+Sum题解题面传送门。题目要求有多少对\((l,r)\)满足\(1\lel\ler\len\)且\(\sum_{i=l}^{r}{b_i}+\min_{i=l}^{r}{a_i}\leS\)。考虑CDQ分治,那么我们需要不断寻找有多少对\((l,r)\)满足\(L\lel\leM<r\leR\)且\(\sum_{i=l}^{r}{b......
  • P9836 种树 题解
    题目传送门前置知识质因数分解。贪心。题解思路先来解决一个问题,统计一个数\(x\)的正因数个数。可以将\(x\)质因数分解,得到每个数在\(x\)的质因数分解中出现了多少次。都知道质因数分解是每个数的唯一分解,那么统计个数的时候就只需要枚举每个质因数的出现个数。所以......
  • CF510C Fox And Names 题解
    CF510CFoxAndNames题解https://www.luogu.com.cn/problem/CF510C思路题意就是:确定一个小写字母的比较规则,使得给定的所有字符串在一开始就是按你确定的比较规则排序了的。可以发现:对于前后一对字符串,找到第一对不同的字符,是要这两个字符有合法的大小关系,就能满足题意。......
  • CF383C Propagating tree 题解
    题目链接:CF或者洛谷比较朴素的题,注意到这个涉及到子树变化,我们考虑优先处理出\(dfs\)序,方便处理。注意到第一个问题较为繁琐,我们着重解决下第一个问题。在树上问题,我们这种间隔点常常使用\(deep\)进行区分。根的\(deep\)为奇数,那么对自己子树范围内的奇数\(deep\)......
  • P2487 [SDOI2011] 拦截导弹 题解
    题目链接:拦截导弹约定:本题中提到的\(LDS\)和\(LIS\)不是严格单调,而是非严格单调,即为\(\le或者\ge\)。比较神奇的题,问的东西比较多,我们逐渐拆分:对于第一个问题而言,这个dp方程是很好写的:\[dp[i]=\max{dp[j]}+1(i<j,h[i]\leh[j],v[i]\lev[j])\]其中\(dp[i]\)即......
  • 题解 gym102900J 【Octasection】
    代码:#include<iostream>#include<algorithm>#include<stack>#include<vector>#include<cstdio>usingnamespacestd;typedefstructRectangle_tag{ intx1; intx2; inty1; inty2; Rectangle_tag(intx1_,intx2_,int......
  • 24冬网络流复习题解
    A是谁瞪了半个小时不会*2000呀,是谁呀是谁呀。感觉这题比部分紫题都难。。。首先发现选取字符的顺序并不重要,所以\(t\)可以看成\(26\)个字符要选的个数。设字符\(c\)出现了\(x\)次,那么直接向汇点连流量为\(x\)费用为\(0\)的边。然后考虑\(s_i\)与每个字符的关......
  • 2024年2月28号题解
    P4994终于结束的起点解题思路通过加法同余原理可以知道f[i]%m==0,那么f[i-1]%m=1,所有把f[i+1]%m=1转换成了f[i-1]%m=1的问题那么只需要填好斐波那契数列再判断就可以了,又因为斐波那契可能会超出int的范围那么我们对每一项斐波那契再取模就可以了代码......
  • 旅游景点 Tourist Attractions (壮压 DP)题解
    简化题意题目链接——不卡内存班题目链接——卡内存版给定\(n\)个点和\(m\)条边组成的无向图,按照一定限制要求停留\(2\simk+1\)共\(k\)个点(可以经过但不停留),求最短的从\(1\)出发到\(n\)的路径长。限制情况如下:共有\(q\)个限制,接下来\(q\)行,每行两个数\(x......