当前位置: 首页 > news >正文

洛谷 P2606 [ZJOI2010] 排列计数


题目传送门


前言

ZJ 省十五年前的省选题思路依旧逆天,能通过下标 ⌊ i / 2 ⌋ \lfloor i / 2 \rfloor i/2 想到二叉堆的也是无敌了 (但应该是我太菜了)。为了削减颓题解的负罪学习这种新颖的 d p dp dp 思路,我决定写篇题解。


思路

问题转化

如前言所说,题目让我们构造 p i > p i / 2 p_i > p_{i / 2} pi>pi/2 的序列可以转化为构造一个二叉小根堆

状态设计

d p u dp_u dpu 表示以 u u u 为根节点的子树共有多少种二叉小根堆。

转移方程

假设以 u u u 为根节点的子树大小为 s i z u siz_u sizu

因为要满足小根堆性质,所以说 u u u 的数值必须是所有的 s i z u siz_u sizu 中最小的那一个。
把最小的那个挑出来之后剩下 s i z u − 1 siz_u - 1 sizu1 个,再从中挑 s i z 2 u siz_{2u} siz2u 个来构造左子树,共有 C s i z u − 1 s i z 2 u C_{siz_u - 1} ^ {siz_{2u}} Csizu1siz2u 种可能,剩下的去构造右子树。

因此有:
d p u = d p 2 u × d p 2 u + 1 × C s i z u − 1 s i z 2 u dp_u = dp_{2u} \ \times dp_{2u + 1} \times C_{siz_u - 1} ^ {siz_{2u}} dpu=dp2u ×dp2u+1×Csizu1siz2u

至于怎么求 s i z u siz_u sizu,提前 d f s dfs dfs 预处理一下即可。

复杂度

由于求组合数取模时要用到卢卡斯定理,所以时间复杂度为 O ( n × l o g m ( n ) ) O(n \times log_m(n)) O(n×logm(n)),空间复杂度 O ( n ) O(n) O(n)


代码

#include <bits/stdc++.h>using namespace std;typedef long long ll;const int maxn = 1e6 + 7;ll n, p;
ll siz[maxn];
ll dfs(int u) {siz[u] = 1;if ((u << 1) <= n) siz[u] += dfs(u << 1);if ((u << 1 | 1) <= n) siz[u] += dfs(u << 1 | 1);return siz[u];
}ll fac[maxn], inv[maxn];
ll qpow(ll x,ll y) {ll res = 1;for (; y; y >>= 1, x = x * x % p)if (y & 1) res = res * x % p;return res;
}
void init() {fac[0] = inv[0] = 1;for (ll i = 1; i <= n; ++i) {fac[i] = fac[i - 1] * i % p;inv[i] = qpow(fac[i], p - 2);}
}
ll C(ll x, ll y) {if (x < y) return 0;return fac[x] * inv[x - y] % p * inv[y] % p;
}
ll Lucas(ll x, ll y, ll p) {if (y == 0) return 1;return C(x % p, y % p) * Lucas(x / p, y / p, p) % p;
}ll dp[maxn];
ll DP(int u) {if (u * 2 > n) return 1;if (u * 2 + 1 > n) return 1;
//	DP(u * 2), DP(u * 2 + 1);
//	dp[u] = Lucas(siz[u] - 1, siz[u * 2], p) * dp[u * 2] % p * dp[u * 2 + 1] % p;return Lucas(siz[u] - 1, siz[u * 2], p) * DP(u * 2) % p * DP(u * 2 + 1) % p;
}
int main() {scanf("%lld%lld", &n, &p);dfs(1), init();
//	for (int i = 1; i <= 5; ++i) {
//		for (int j = 1; j <= i; ++j) {
//			printf("C(%d, %d) = %lld\n", i, j, Lucas(i, j, p));
//		}
//	}printf("%lld\n", DP(1));return 0;
}
http://www.xdnf.cn/news/31015.html

相关文章:

  • 第六周作业
  • 详细的PyCharm安装教程
  • STL——红黑树的封装及map/set的模拟实现
  • 重读《人件》Peopleware -(7)Ⅰ管理人力资源Ⅵ-莱特瑞尔 Laetrile
  • 【后端】【python】Python 爬虫常用的框架解析
  • 如何保存服务器mysql数据库的数据到本地文件
  • Java 并发性能优化:线程池的最佳实践
  • nohup的使用
  • MySQL中常用函数的分类及示例
  • rpcrt4!COMMON_AddressManager函数分析之和全局变量rpcrt4!AddressList的关系
  • 面向新一代扩展现实(XR)应用的物联网框架
  • 打靶日记 zico2: 1
  • Qt编写推流程序/支持webrtc265/从此不用再转码/打开新世界的大门
  • 初始 Vue
  • Android 下拉栏中的禁用摄像头和麦克风隐藏
  • PH热榜 | 2025-04-19
  • 实现Azure Databricks安全地请求企业内部API返回数据
  • linux学习 5 正则表达式及通配符
  • 聊聊Spring AI Alibaba的ElasticsearchDocumentReader
  • JavaScript中的Event事件对象详解
  • 自由学习记录(56)
  • 背包 DP 详解
  • 【mongodb】数据库操作
  • TIM_ITConfig() 和 TIM_Cmd()
  • 当HTTP遇到SQL注入:Java开发者的攻防实战手册
  • 实用电脑工具,轻松实现定时操作
  • 《目标检测双雄:YOLO与Faster R-CNN,谁主沉浮?》
  • dotnet core webapi 实现 异常处理中间件
  • [密码学基础]GMT 0002-2012 SM4分组密码算法 技术规范深度解析
  • LNA设计