Codeforces 题面传送门 & 洛谷题面传送门

首先题目中涉及排列的 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!\),后者可以分情况讨论:

  1. 根是析点,那么我们可以枚举根节点的儿子个数 \(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!\)
  2. 根是合点,那么我们不妨假设根节点的儿子排列为 \(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(析合树计数)的更多相关文章

  1. Codeforces 1093E Intersection of Permutations (CDQ分治+树状数组)

    题意:给你两个数组a和b,a,b都是一个n的全排列:有两种操作:一种是询问区间在数组a的区间[l1,r1]和数组b的区间[l2,r2]出现了多少相同的数字,另一种是交换数组b中x位置和y位置的数字. ...

  2. 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 ...

  3. [Codeforces 266E]More Queries to Array...(线段树+二项式定理)

    [Codeforces 266E]More Queries to Array...(线段树+二项式定理) 题面 维护一个长度为\(n\)的序列\(a\),\(m\)个操作 区间赋值为\(x\) 查询\ ...

  4. [Codeforces 280D]k-Maximum Subsequence Sum(线段树)

    [Codeforces 280D]k-Maximum Subsequence Sum(线段树) 题面 给出一个序列,序列里面的数有正有负,有两种操作 1.单点修改 2.区间查询,在区间中选出至多k个不 ...

  5. codeforces 1217E E. Sum Queries? (线段树

    codeforces 1217E E. Sum Queries? (线段树 传送门:https://codeforces.com/contest/1217/problem/E 题意: n个数,m次询问 ...

  6. Codeforces 311D Interval Cubing 数学 + 线段树 (看题解)

    Interval Cubing 这种数学题谁顶得住啊. 因为 (3 ^ 48) % (mod - 1)为 1 , 所以48个一个循环节, 用线段树直接维护. #include<bits/stdc ...

  7. Codeforces Round #285 (Div.1 B & Div.2 D) Misha and Permutations Summation --二分+树状数组

    题意:给出两个排列,求出每个排列在全排列的排行,相加,模上n!(全排列个数)得出一个数k,求出排行为k的排列. 解法:首先要得出定位方法,即知道某个排列是第几个排列.比如 (0, 1, 2), (0, ...

  8. Codeforces Round #337 Alphabet Permutations

    E. Alphabet Permutations time limit per test:  1 second memory limit per test:  512 megabytes input: ...

  9. Codeforces 588E. A Simple Task (线段树+计数排序思想)

    题目链接:http://codeforces.com/contest/558/problem/E 题意:有一串字符串,有两个操作:1操作是将l到r的字符串升序排序,0操作是降序排序. 题解:建立26棵 ...

随机推荐

  1. 12. 亿级流量电商系统JVM模型参数二次优化

    亿级流量电商系统JVM模型参数预估方案,在原来的基础上采用ParNew+CMS垃圾收集器 一.亿级流量分析及jvm参数设置 1. 需求分析 大促在即,拥有亿级流量的电商平台开发了一个订单系统,我们应该 ...

  2. 【Spring】重新认识 IoC

    前言 IoC (Inversion of control) 并不是Spring特有的概念. IoC 维基百科的解释: In software engineering, inversion of con ...

  3. 改善深层神经网络-week2编程题(Optimization Methods)

    1. Optimization Methods Gradient descent goes "downhill" on a cost function \(J\). Think o ...

  4. 你知道什么是JUC了吗?

    多线程一直Java开发中的难点,也是面试中的常客,趁着还有时间,打算巩固一下JUC方面知识,我想机会随处可见,但始终都是留给有准备的人的,希望我们都能加油!!! 沉下去,再浮上来,我想我们会变的不一样 ...

  5. [no_code][Beta]设计和计划

    2020春季计算机学院软件工程(罗杰 任健) 2020春季计算机学院软件工程(罗杰 任健) 作业要求 Beta设计和计划 我们在这个课程的目标是 远程协同工作,采用最新技术开发软件 这个作业在哪个具体 ...

  6. VUE调用子窗口弹窗或组件弹窗,关闭弹窗刷新父级页面主页面,通过this.$emit来实现

    this.$emit是父级向自己传值 第一步在父级页面创建自己页面的引用 <template> <div> <edit ref="edit" @ref ...

  7. window系统上实现mongodb副本集的搭建

    一.问题引出 假设我们生产上的mongodb是单实例在跑,如果此时发生网络发生问题或服务器上的硬盘发生了损坏,那么这个时候我们的mongodb就使用不了.此时我们就需要我们的mongodb实现高可用, ...

  8. VS2019、Qt5.12及QGis3.16开发常见问题汇总

    在C++.Qt软件开发过程中,常常遇到一些编译错误或警告:本文将VS2019.Qt5.12.10和QGis3.16.10的二次开发过程常见的问题做了整理,供大家参考,也便于日后查阅.该内容分为四部分: ...

  9. single-number leetcode C++

    Given an array of integers, every element appears twice except for one. Find that single one. Note: ...

  10. 百亿级小文件存储,JuiceFS 在自动驾驶行业的最佳实践

    自动驾驶是最近几年的热门领域,专注于自动驾驶技术的创业公司.新造车企业.传统车厂都在这个领域投入了大量的资源,推动着 L4.L5 级别自动驾驶体验能尽早进入我们的日常生活. 自动驾驶技术实现的核心环节 ...