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\)。

简单递推一下即可,复杂度三方。

  1. const int MAXN=400;
  2. int mod,fac[MAXN+5],ifac[MAXN+5],dp[MAXN+5],s[MAXN+5][MAXN+5],f[MAXN+5];
  3. void init(int n){
  4. for(int i=(fac[0]=ifac[0]=ifac[1]+1);i<=n;i++) ifac[i]=1ll*ifac[mod%i]*(mod-mod/i)%mod;
  5. for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%mod,ifac[i]=1ll*ifac[i-1]*ifac[i]%mod;
  6. f[1]=1;
  7. for(int i=2;i<=n;i++){
  8. for(int j=1;j<i;j++) f[i]=(f[i]+1ll*f[j]*fac[i-j])%mod;
  9. f[i]=(fac[i]-f[i]+mod)%mod;
  10. } s[0][0]=1;
  11. for(int i=1;i<=n;i++) for(int j=1;j<=i;j++) for(int k=1;k<=i;k++)
  12. s[i][j]=(s[i][j]+1ll*s[i-k][j-1]*fac[k])%mod;
  13. dp[2]=(dp[1]=(dp[3]=0)+1)+1;
  14. for(int i=4;i<=n;i++){
  15. int sum1=0,sum2=0;
  16. for(int j=1;j<i;j++) sum1=(sum1+1ll*f[j]*fac[i-j])%mod;
  17. for(int j=4;j<i;j++) sum2=(sum2+1ll*dp[j]*s[i][j])%mod;
  18. int sub=(2ll*sum1+sum2)%mod;dp[i]=(fac[i]-sub+mod)%mod;
  19. }
  20. }
  21. int main(){
  22. int qu;scanf("%d%d",&qu,&mod);init(MAXN);
  23. while(qu--){
  24. int n;scanf("%d",&n);
  25. printf("%d\n",dp[n]);
  26. }
  27. return 0;
  28. }

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. jmeter基础功能及认识

    1.基础知识: JMeter是免费开源的,纯java开发的性能测试工具,可以测试静态和动态的资源,例如:静态文件.java服务小程序.CGI脚本.java对象.数据库.FTP服务器.邮件服务器和Per ...

  2. 【UE4】GAMES101 图形学作业2:光栅化和深度缓存

    总览 在上次作业中,虽然我们在屏幕上画出一个线框三角形,但这看起来并不是那么的有趣.所以这一次我们继续推进一步--在屏幕上画出一个实心三角形,换言之,栅格化一个三角形.上一次作业中,在视口变化之后,我 ...

  3. Sequence Model-week1编程题2-Character level language model【RNN生成恐龙名 LSTM生成莎士比亚风格文字】

    Character level language model - Dinosaurus land 为了构建字符级语言模型来生成新的名称,你的模型将学习不同的名字,并随机生成新的名字. 任务清单: 如何 ...

  4. UltraSoft - Beta - 设计与计划

    在DDL Killer的Alpha发布版本一周后,我们积累了一定的用户数量和用户反馈,同时也着手准备Beta阶段的继续开发,在正式开始迭代前,先对我们的Beta阶段的需求做一个统计和预估,一是保证工作 ...

  5. UltraSoft - Alpha - Scrum Meeting 4

    Date: Apr 18th, 2020. 会议内容为 例行汇报. Scrum 情况汇报 进度情况 组员 负责 前两日进度 后两日任务 CookieLau PM 完成前后端交互规格的约定,了解前后端进 ...

  6. [对对子队]会议记录5.16(Scrum Meeting3)

    今天已完成的工作 何瑞 ​ 工作内容:搭建关卡5.6,优化之前的成本系统 ​ 相关issue:搭建关卡4.5.6 ​ 相关签入:feat: 第五第六关搭建完成 吴昭邦 ​ 工作内容:搭建关卡5.6 ​ ...

  7. 助你上手Vue3全家桶之Vue-Router4教程

    目录 1,前言 1,Router 2.1,跳转 2.2,打开新页面 3,Route 4,守卫 4.1,onBeforeRouteLeave 4.2,onBeforeRouteUpdate 4.3,路由 ...

  8. 清除行列 牛客网 程序员面试金典 C++ Python

    清除行列 牛客网 程序员面试金典 C++ Python 题目描述 请编写一个算法,若N阶方阵中某个元素为0,则将其所在的行与列清零. 给定一个N阶方阵int[]mat和矩阵的阶数n,请返回完成操作后的 ...

  9. 最接近的数 牛客网 程序员面试金典 C++ Python

    最接近的数 牛客网 程序员面试金典 C++ Python 题目描述 有一个正整数,请找出其二进制表示中1的个数相同.且大小最接近的那两个数.(一个略大,一个略小) 给定正整数int x,请返回一个ve ...

  10. 组件通过props属性传值

    组件之间的传值 组件是一个单独功能模块的封装,有属于自己的data和methods,一个组件的 data 选项必须是一个函数 为什么必须是函数:因为只有当data是函数时,不同实例调用同一个组件时才会 ...