洛谷P2606 [ZJOI2010]排列计数 组合数学+DP
题意:称一个1,2,...,N的排列P1,P2...,Pn是Magic的,当且仅当2<=i<=N时,Pi>Pi/2. 计算1,2,...N的排列中有多少是Magic的,答案可能很大,只能输出模P以后的值。
解法:我们仔细观察这个pi>=pi/2,想到什么了?像不像二叉树中每个点i和它的两个儿子的编号2i和2i+1。
那么我们可以想象每个点i想它的两个儿子2i/2i+1连边,加上Pi>Pi/2这个条件,那么这棵二叉树就是一棵小根堆。那么我们考虑用dp解决这道题,
设dp[i]表示i个不同的数组成一棵大小为i的小根堆的方案数,状态转移方程为dp[i]=C(i-1,l[i]) * dp[l[i]] * dp[r[i]] ;解释一下:这里的l[i]/r[i]代表大小为i的完全二叉树(为什么要是完全的?因为题目要求的序号是连续的)的左/右子树大小。这个方程的意思是从i-1个数里面选择l[i]个数作为左子树方案数乘以剩下r[i]个数作为右子树方案数。
那么我们预处理l[i]/r[i]就可以计算答案了。
注意此题p有可能>=n,所以要用Lucas定理计算组合数。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e6+;
int n,P,l[N],r[N],dp[N]; int power(int x,int p) {
int ret=;
for (;p;p>>=) {
if (p&) ret=(LL)ret*x%P;
x=(LL)x*x%P;
}
return ret;
} int fac[N],inv[N];
void prework(int n) {
fac[]=; inv[]=;
for (int i=;i<=n;i++) {
fac[i]=(LL)i*fac[i-]%P;
inv[i]=power(fac[i],P-);
}
l[]=;
for(int i=,g=;i<=n;g<<=,i+=g) {
for(int j=;j<=g;j++) l[i+j-]=l[i+j-]+;
for(int j=;j<=g;j++) l[i+g+j-]=l[i+g+j-];
}
for (int i=;i<=n;i++) r[i]=i--l[i];
} int C(int n,int m) {
if (n>=P || m>=P) return (LL)C(n/P,m/P)*C(n%P,m%P)%P;
else return (LL)fac[n]*inv[m]%P*inv[n-m]%P;
} int main()
{
cin>>n>>P;
prework(n);
dp[]=dp[]=;
for (int i=;i<=n;i++)
dp[i]=(LL)C(i-,l[i])*dp[l[i]]%P*dp[r[i]]%P;
cout<<dp[n]<<endl;
return ;
}
洛谷P2606 [ZJOI2010]排列计数 组合数学+DP的更多相关文章
- 洛谷P2606 [ZJOI2010]排列计数(组合数 dp)
题意 题目链接 称一个1,2,...,N的排列P1,P2...,Pn是Magic的,当且仅当2<=i<=N时,Pi>Pi/2. 计算1,2,...N的排列中有多少是Magic的,答案 ...
- 洛谷 P2606 [ZJOI2010]排列计数 解题报告
P2606 [ZJOI2010]排列计数 题目描述 称一个\(1,2,...,N\)的排列\(P_1,P_2...,P_n\)是\(Magic\)的,当且仅当对所以的\(2<=i<=N\) ...
- ●洛谷P2606 [ZJOI2010]排列计数
题链: https://www.luogu.org/problemnew/show/P2606题解: 组合数(DP),Lucas定理 首先应该容易看出,这个排列其实是一个小顶堆. 然后我们可以考虑dp ...
- 洛谷P2606 [ZJOI2010]排列计数(数位dp)
题目描述 称一个1,2,...,N的排列P1,P2...,Pn是Magic的,当且仅当2<=i<=N时,Pi>Pi/2. 计算1,2,...N的排列中有多少是Magic的,答案可能很 ...
- 洛谷P2606 [ZJOI2010]排列计数
题目描述 称一个1,2,...,N的排列P1,P2...,Pn是Magic的,当且仅当2<=i<=N时,Pi>Pi/2. 计算1,2,...N的排列中有多少是Magic的,答案可能很 ...
- 洛谷P4071 [SDOI2016] 排列计数 [组合数学]
题目传送门 排列计数 题目描述 求有多少种长度为 n 的序列 A,满足以下条件: 1 ~ n 这 n 个数在序列中各出现了一次 若第 i 个数 A[i] 的值为 i,则称 i 是稳定的.序列恰好有 m ...
- 洛谷P2602 [ZJOI2010]数字计数(数位dp)
数字计数 题目传送门 解题思路 用\(dp[i][j][k]\)来表示长度为\(i\)且以\(j\)为开头的数里\(k\)出现的次数. 则转移方程式为:\(dp[i][j][k] += \sum_{t ...
- P2606 [ZJOI2010]排列计数
P2606 [ZJOI2010]排列计数 因为每个结点至多有一个前驱,所以我们可以发现这是一个二叉树.现在我们要求的就是以1为根的二叉树中,有多少种情况,满足小根堆的性质. 设\(f(i)\)表示以\ ...
- 洛谷P2602 [ZJOI2010]数字计数 题解 数位DP
题目链接:https://www.luogu.com.cn/problem/P2602 题目大意: 计算区间 \([L,R]\) 范围内 \(0 \sim 9\) 各出现了多少次? 解题思路: 使用 ...
随机推荐
- 通过java反射机制,修改年龄字段的值
需求:将生日转为年龄 /** * 获取年龄值 */ public List getAgeInfo(List list) throws Exception { if (null == list || l ...
- vue引入静态js文件
由于一些演示,需要对编码名称等可快速进行修改,需要页面方便配置.由于build后的vue项目基本已经看不出原样,因此需要创建一个文件,并在打包的时候不会进行编译. vue-cli 2.0的作法是在st ...
- 像计算机科学家一样思考python-第3章 函数
在程序设计中,函数是指用于进行某种计算的一系列语句的有名称的组合.定义一个函数时,需要指定函数的名称并写下一系列程序语句.之后,就可以使用名称来“调用”这个函数 3.1函数调用 一个函数调用的例子 & ...
- Java 位运算超全面总结
1.原码.反码.补码 关于原码.反码.补码的相关知识作者不打算在这里长篇大论,相关知识已有别的大佬总结很好了,还请老铁自行 Google,不过有篇知乎回答是作者学编程以来见过对相关知识最通俗易懂,生动 ...
- Linux_VMWare12 Install RHEL7
目录 目录 前言 Install RHEL7 前言 准备考试,顺便来一波VMWare安装虚拟机的图文详解. Install RHEL7 step1. 选择自定义安装,Next step2. 版本兼容性 ...
- 分布式ID生成 - 雪花算法
雪花算法是一种生成分布式全局唯一ID的经典算法,关于雪花算法的解读网上多如牛毛,大多抄来抄去,这里请参考耕耘的小象大神的博客ID生成器,Twitter的雪花算法(Java) 网上的教程一般存在两个问题 ...
- SoapUI常用的参数化方法
本篇文章来讲一下SoapUI在使用中常用的参数化方法字段参数化和使用DataSource调用Excel中的 数据给接口参数化,其中DataSource功能SoapUI开源版没有,大家可以使用破解版, ...
- Learn Python the hard way, ex42 物以类聚
依然少打很多剧情,并修改了很多,还好,能运行 #!urs/bin/python #coding:utf-8 from sys import exit from random import randin ...
- HDU-1394 Minimum Inversion Number (逆序数,线段树或树状数组)
The inversion number of a given number sequence a1, a2, ..., an is the number of pairs (ai, aj) that ...
- 搜索---DFS
DFS 广度优先一层一层遍历,每一层得到的所有新节点,要用队列存储起来以备下一层遍历的时候再遍历. 而深度优先遍历搜索在得到一个新节点时立即对新节点进行遍历:从节点0出发开始遍历,得到新节点6 ...