Codeforces 1089I - Interval-Free Permutations(析合树计数)
首先题目中涉及排列的 interval,因此可以想到析合树。由于本蒟蒻太菜了以至于没有听过这种神仙黑科技,因此简单介绍一下这种数据结构:我们注意到排列的区间有一个性质:对于排列中的两段区间 \(X,Y\),如果它们有交,那么必然有 \(X\cap Y,X\cup Y,X\setminus(X\cap Y),Y\setminus(X\cap Y)\) 四个集合均为区间,也就是说连续段之间只有包含没有相交关系,因此它们可以表示为一棵树形结构。
我们考虑用一棵根节点为区间 \([1,n]\),叶子节点为每个长度为 \(1\) 的区间的树表示这个树形结构,对于每个区间我们定义它的本原连续段为极大的、彼此之间不存在部分相交的连续段,举个例子,排列 \([5,1,4,2,3]\) 有两个本原连续段:\([5],[1,4,2,3]\)——显然我们能够找到这样的连续段组成的集合。那么我们就令这个区间的儿子为这些本原连续段们,继续递归下去即可建出这棵树。由于这棵树的叶子节点恰有 \(n\) 个,因此这棵树的节点数也是线性的。
考虑将这棵树的节点分分类,由于每个节点的儿子们都是一个个区间,因此我们可以将它们离散化成一个个在 \([1,\text{儿子个数}]\) 之内的数,我们称这样得到的排列为儿子排列,手玩几组数据即可发现对于每个点而言,它的儿子排列总共只有两种类型,否则就不满足“本原连续段”的定义了:
- 儿子排列从左到右恰好为 \(1,2,3,\cdots,\text{儿子个数}\) 或者 \(\text{儿子个数},\cdots,3,2,1\),我们称这样的点为合点
- 儿子排列中除了整个区间和长度为 \(1\) 的子区间不存在任何其他连续段,我们称这样的点为析点
比方说排列 \([9,1,10,3,2,5,7,6,8,4]\) 建出树来如下图所示:
析合树有以下性质:
- 每个析点儿子个数一定 \(\ge 4\),因为任何长度为 \(3\) 的排列都存在非平凡连续段
- 如果我们指定一棵树上每个节点的析合性,并满足析点儿子个数 \(\ge 4\),合点儿子个数 \(\ge 2\),那么一定存在某个排列对应这棵树
回到此题来,此题等价于求儿子个数为 \(n\),且根为析点的排列个数 \(f_n\),直接求不太容易,因此考虑正难则反,那总排列数减去不合法的排列个数,前者就是 \(n!\),后者可以分情况讨论:
- 根是析点,那么我们可以枚举根节点的儿子个数 \(c\ge 4\),那么我们要将 \(n\) 个节点划分成 \(c\) 个区间,每个区间内的元素随便乱排,最后还要将这 \(c\) 个区间排成一列满足不存在非平凡区间,很显然我们可以将这个任务分成两部分,划分儿子和确定儿子排列,后者方案数显然就是 \(f_c\),前者可以设一个 \(s_{i,j}\) 表示将 \(i\) 个节点划分成 \(j\) 段的方案数,显然有 \(s_{i,j}=\sum\limits_{k<i}s_{i-k,j-1}·k!\)
- 根是合点,那么我们不妨假设根节点的儿子排列为 \(1,2,3,\cdots\),对于单调递减的情况乘个 \(2\) 即可,根据合点的定义必然存在某个前缀 \(i\) 满足 \(p[1...i]\) 恰好为 \([1,i]\) 的排列,我们就考虑枚举这个最小的 \(i\),记 \(g_i\) 为长度为 \(i\) 的、且存在某个长度不等于 \(i\) 的前缀 \(p[1...j]\) 为 \([1,j]\) 的排列的排列 \(p\) 的个数,那么有 \(g_i=i!-\sum\limits_{j<i}g_j(i-j)!\),根是合点的总数也就自然是 \(2g_n\)。
简单递推一下即可,复杂度三方。
const int MAXN=400;
int mod,fac[MAXN+5],ifac[MAXN+5],dp[MAXN+5],s[MAXN+5][MAXN+5],f[MAXN+5];
void init(int n){
for(int i=(fac[0]=ifac[0]=ifac[1]+1);i<=n;i++) ifac[i]=1ll*ifac[mod%i]*(mod-mod/i)%mod;
for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%mod,ifac[i]=1ll*ifac[i-1]*ifac[i]%mod;
f[1]=1;
for(int i=2;i<=n;i++){
for(int j=1;j<i;j++) f[i]=(f[i]+1ll*f[j]*fac[i-j])%mod;
f[i]=(fac[i]-f[i]+mod)%mod;
} s[0][0]=1;
for(int i=1;i<=n;i++) for(int j=1;j<=i;j++) for(int k=1;k<=i;k++)
s[i][j]=(s[i][j]+1ll*s[i-k][j-1]*fac[k])%mod;
dp[2]=(dp[1]=(dp[3]=0)+1)+1;
for(int i=4;i<=n;i++){
int sum1=0,sum2=0;
for(int j=1;j<i;j++) sum1=(sum1+1ll*f[j]*fac[i-j])%mod;
for(int j=4;j<i;j++) sum2=(sum2+1ll*dp[j]*s[i][j])%mod;
int sub=(2ll*sum1+sum2)%mod;dp[i]=(fac[i]-sub+mod)%mod;
}
}
int main(){
int qu;scanf("%d%d",&qu,&mod);init(MAXN);
while(qu--){
int n;scanf("%d",&n);
printf("%d\n",dp[n]);
}
return 0;
}
Codeforces 1089I - Interval-Free Permutations(析合树计数)的更多相关文章
- Codeforces 1093E Intersection of Permutations (CDQ分治+树状数组)
题意:给你两个数组a和b,a,b都是一个n的全排列:有两种操作:一种是询问区间在数组a的区间[l1,r1]和数组b的区间[l2,r2]出现了多少相同的数字,另一种是交换数组b中x位置和y位置的数字. ...
- Codeforces 500D New Year Santa Network(树 + 计数)
D. New Year Santa Network time limit per test 2 seconds memory limit per test 256 megabytes input st ...
- [Codeforces 266E]More Queries to Array...(线段树+二项式定理)
[Codeforces 266E]More Queries to Array...(线段树+二项式定理) 题面 维护一个长度为\(n\)的序列\(a\),\(m\)个操作 区间赋值为\(x\) 查询\ ...
- [Codeforces 280D]k-Maximum Subsequence Sum(线段树)
[Codeforces 280D]k-Maximum Subsequence Sum(线段树) 题面 给出一个序列,序列里面的数有正有负,有两种操作 1.单点修改 2.区间查询,在区间中选出至多k个不 ...
- codeforces 1217E E. Sum Queries? (线段树
codeforces 1217E E. Sum Queries? (线段树 传送门:https://codeforces.com/contest/1217/problem/E 题意: n个数,m次询问 ...
- Codeforces 311D Interval Cubing 数学 + 线段树 (看题解)
Interval Cubing 这种数学题谁顶得住啊. 因为 (3 ^ 48) % (mod - 1)为 1 , 所以48个一个循环节, 用线段树直接维护. #include<bits/stdc ...
- Codeforces Round #285 (Div.1 B & Div.2 D) Misha and Permutations Summation --二分+树状数组
题意:给出两个排列,求出每个排列在全排列的排行,相加,模上n!(全排列个数)得出一个数k,求出排行为k的排列. 解法:首先要得出定位方法,即知道某个排列是第几个排列.比如 (0, 1, 2), (0, ...
- Codeforces Round #337 Alphabet Permutations
E. Alphabet Permutations time limit per test: 1 second memory limit per test: 512 megabytes input: ...
- Codeforces 588E. A Simple Task (线段树+计数排序思想)
题目链接:http://codeforces.com/contest/558/problem/E 题意:有一串字符串,有两个操作:1操作是将l到r的字符串升序排序,0操作是降序排序. 题解:建立26棵 ...
随机推荐
- 12. 亿级流量电商系统JVM模型参数二次优化
亿级流量电商系统JVM模型参数预估方案,在原来的基础上采用ParNew+CMS垃圾收集器 一.亿级流量分析及jvm参数设置 1. 需求分析 大促在即,拥有亿级流量的电商平台开发了一个订单系统,我们应该 ...
- 【Spring】重新认识 IoC
前言 IoC (Inversion of control) 并不是Spring特有的概念. IoC 维基百科的解释: In software engineering, inversion of con ...
- 改善深层神经网络-week2编程题(Optimization Methods)
1. Optimization Methods Gradient descent goes "downhill" on a cost function \(J\). Think o ...
- 你知道什么是JUC了吗?
多线程一直Java开发中的难点,也是面试中的常客,趁着还有时间,打算巩固一下JUC方面知识,我想机会随处可见,但始终都是留给有准备的人的,希望我们都能加油!!! 沉下去,再浮上来,我想我们会变的不一样 ...
- [no_code][Beta]设计和计划
2020春季计算机学院软件工程(罗杰 任健) 2020春季计算机学院软件工程(罗杰 任健) 作业要求 Beta设计和计划 我们在这个课程的目标是 远程协同工作,采用最新技术开发软件 这个作业在哪个具体 ...
- VUE调用子窗口弹窗或组件弹窗,关闭弹窗刷新父级页面主页面,通过this.$emit来实现
this.$emit是父级向自己传值 第一步在父级页面创建自己页面的引用 <template> <div> <edit ref="edit" @ref ...
- window系统上实现mongodb副本集的搭建
一.问题引出 假设我们生产上的mongodb是单实例在跑,如果此时发生网络发生问题或服务器上的硬盘发生了损坏,那么这个时候我们的mongodb就使用不了.此时我们就需要我们的mongodb实现高可用, ...
- VS2019、Qt5.12及QGis3.16开发常见问题汇总
在C++.Qt软件开发过程中,常常遇到一些编译错误或警告:本文将VS2019.Qt5.12.10和QGis3.16.10的二次开发过程常见的问题做了整理,供大家参考,也便于日后查阅.该内容分为四部分: ...
- single-number leetcode C++
Given an array of integers, every element appears twice except for one. Find that single one. Note: ...
- 百亿级小文件存储,JuiceFS 在自动驾驶行业的最佳实践
自动驾驶是最近几年的热门领域,专注于自动驾驶技术的创业公司.新造车企业.传统车厂都在这个领域投入了大量的资源,推动着 L4.L5 级别自动驾驶体验能尽早进入我们的日常生活. 自动驾驶技术实现的核心环节 ...