题目

  点这里看题目。

分析

  我们不妨来考虑一下生成的序列有什么性质。

  为了方便表示,我们将序列\(S\)的第\(i\)项写为\(S[i]\)。

  首先考虑如果所有的\(A\)序列都是递增的,那么我们得到的序列肯定是递增的。如果存在递减的情况,例如其中某个序列\(B\in\{A_1,A_2,\dots,A_n\}\),存在\(B[1]>B[2]\)。那么按照取数规则,我们一旦取出了\(B[1]\),我们就一定会取出\(B[2]\)。这个比较显然。这是因为\(B[1]\)被取出的时候,其他所有序列的第一个元素肯定都大于\(B[1]\),因此也肯定大于\(B[2]\)。

  我们发现只要序列中存在\(B[1]>B[2]\)或者\(B[2]>B[3]\),这两个数就会被相邻地取出;如果存在\(B[1]>B[2]\)且\(B[1]>B[3]\),这三个数也会被相邻取出。我们将这种必然相邻取出的情况分进一个组里面。

  注意到组只会有长度为 1 ,长度为 2 ,长度为 3 三种,而且由于一个长度为 2 的组一定和一个长度为 1 的组成对出现,因此长度为 2 的组的数量一定不超过长度为 1 的组的数量。

  我们可以发现,这样的组在构造的过程中,一定会按照组的第一个元素的大小进行排序构造出一个排列来。因此,一些组如果合法,就可以唯一确定一个排列。因此,我们可以通过计算组的合法构造方案来计算可生成的排列方案数。

  我们有两种方法来解决这个问题:

1.DP

  我们需要将\([1,3n]\)划分成若干组,限制如下:

   1. 每一组的长度不超过3。

   2. 每一组的第一个数一定是这一组中最大的。

   3. 长度为 2 的组的数量不超过长度为 1 的组的数量。

  因此我们可以设计如下的 DP 方案:

  \(f(i,j)\):前\(i\)个数分组,满足长度为 1 的组的数量减去长度为 2 的组的数量为\(j\)的方案数。

  转移实际上是考虑最后一个数会怎样分组。转移如下:

\[f(i,j)=f(i-1,j-1)+(i-1)f(i-2,j+1)+(i-1)(i-2)f(i-3,j)
\]

  答案是\(\sum_{i=0}^{3n}f(3n,i)\)。DP 的时间是\(O(n^2)\)。

2.枚举

  这其实是我自己口胡的。

  建议写第一种方法

  由于\(n\)很小,我们可以直接枚举长度为 2 的组的数量和长度为 3 的组的数量(需要满足长度为 2 的组的数量不超过长度为 1 的数量这一前提)。设\(f(n)\)为\(2n\)个数全部分为长度为 2 的组的方案数。转移大概如下:

\[f(n)=f(n-1)+(2n-2)(2n-3)f(n-2)
\]

  \(g(n)\)为\(3n\)个数全部分为长度为 3 的组的方案数,转移类似。这样预处理完之后就可以枚举组的数量了。答案:

\[\sum_{i=0}^{\lfloor\frac {3n}2\rfloor}\sum_{j=0}^{\lfloor\frac{3n-2i}3\rfloor}[3n-2i-3j\ge2i]C_{3n}^{2i}\times C_{3n-2i}^{3j}\times f(i)\times g(j)
\]

  时间是\(O(n^2)\)。

  如果有问题请轻喷,我也没有试过这个方法。

代码

#include <cstdio>

const int MAXN = 6005;

template<typename _T>
void read( _T &x )
{
x = 0;char s = getchar();int f = 1;
while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}
while( s >= '0' && s <= '9' ){x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar();}
x *= f;
} template<typename _T>
void write( _T x )
{
if( x < 0 ){ putchar( '-' ); x = ( ~ x ) + 1; }
if( 9 < x ){ write( x / 10 ); }
putchar( x % 10 + '0' );
} int f[MAXN][MAXN << 1];
int N, M; void add( int &x, const int v ) { x += v; if( x >= M ) x -= M; } int main()
{
read( N ), read( M );
int t = N * 3;
f[0][t] = 1;
for( int i = 1 ; i <= t ; i ++ )
for( int j = - t ; j <= t ; j ++ )
{
if( j > -t ) add( f[i][j + t], f[i - 1][j + t - 1] ); //长度为1
if( j < t && i >= 2 ) add( f[i][j + t], 1ll * f[i - 2][j + t + 1] * ( i - 1 ) % M ); //长度为2
if( i >= 3 ) add( f[i][j + t], 1ll * f[i - 3][j + t] * ( i - 1 ) % M * ( i - 2 ) % M ); //长度为3
}
int ans = 0;
for( int i = 0 ; i <= t ; i ++ ) add( ans, f[t][i + t] );
write( ans ), putchar( '\n' );
return 0;
}

[AGC043-D]Merge Triplets的更多相关文章

  1. AT5801 [AGC043D] Merge Triplets

    这种排列生成排列的题目我们一般可以考虑生成排列合法的充要条件. 首先可以发现的一点就是该生成排列的任意一个数 \(p_i\) 一定不存在连续的三个数 \(p_{i + 1}, p_{i + 2}, p ...

  2. [算法]——归并排序(Merge Sort)

    归并排序(Merge Sort)与快速排序思想类似:将待排序数据分成两部分,继续将两个子部分进行递归的归并排序:然后将已经有序的两个子部分进行合并,最终完成排序.其时间复杂度与快速排序均为O(nlog ...

  3. SQL 提示介绍 hash/merge/concat union

    查询提示一直是个很有争议的东西,因为他影响了sql server 自己选择执行计划.很多人在问是否应该使用查询提示的时候一般会被告知慎用或不要使用...但是个人认为善用提示在不修改语句的条件下,是常用 ...

  4. Merge Sorted Array

    Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array. Note:Yo ...

  5. SQL Tuning 基础概述06 - 表的关联方式:Nested Loops Join,Merge Sort Join & Hash Join

    nested loops join(嵌套循环)   驱动表返回几条结果集,被驱动表访问多少次,有驱动顺序,无须排序,无任何限制. 驱动表限制条件有索引,被驱动表连接条件有索引. hints:use_n ...

  6. Git 少用 Pull 多用 Fetch 和 Merge

    本文有点长而且有点乱,但就像Mark Twain Blaise Pascal的笑话里说的那样:我没有时间让它更短些.在Git的邮件列表里有很多关于本文的讨论,我会尽量把其中相关的观点列在下面. 我最常 ...

  7. Merge 的小技巧

    今天跟大家分享一下搬动数据使用Merge的方法. 有些时候,当我们做数据搬动的时候,有时候做测试啊,换对象啊,就会存在有时候外键存在,不知道怎么对应的关系.比如我现在有架构相同的两组table , A ...

  8. [LeetCode] Merge Sorted Array 混合插入有序数组

    Given two sorted integer arrays A and B, merge B into A as one sorted array. Note:You may assume tha ...

  9. [LeetCode] Merge Intervals 合并区间

    Given a collection of intervals, merge all overlapping intervals. For example, Given [1,3],[2,6],[8, ...

随机推荐

  1. How To Mitigate Slow HTTP DoS Attacks in Apache HTTP Server

    http://www.acunetix.com/blog/web-security-zone/articles/slow-http-dos-attacks-mitigate-apache-http-s ...

  2. [!] Unable to find a pod with name, author, summary, or description matching `AFNetworking`

    大量的答案是删除~/Library/Caches/CocoaPods/search_index.json  没有起作用 有用答案: https://blog.csdn.net/qq_35827461/ ...

  3. VueRouter小手册

    目录 一. 了解router 二. 工作流程 三. 简单的Demo 四. 理解template和route的组合 五. Vue-Router-GoBack记录返回 六. Router-Link 七. ...

  4. Hyperledger Fabric——balance transfer(五)执行交易

    链码安装和实例化之后就可以调用chaincode执行交易,下面分析简单的账户转账操作是如何完成的. 源码分析 1.首先看app.js的路由函数 app.post('/channels/:channel ...

  5. python+selenium实现百度关键词搜索自动化操作

    缘起 之前公司找外面网络公司做某些业务相关关键词排名,了解了一下相关的情况,网络公司只需要我们提供网站地址和需要做的关键词即可,故猜想他们采取的方式应该是通过模拟用户搜索提升网站权重进而提升排名. 不 ...

  6. 在win10上搭建pyspark,

    最近在研究Spark,准确的说是pyspark,为了搭个测试环境,之前一直在云上开Linux机器来搭Hadoop,但是Spark可以Local执行,我就打算在本地搭个环境.遇到了一些问题,记录一下,也 ...

  7. 在 Linux 系统中如何管理 systemd 服务

    在上一篇文章<Linux的运行等级与目标>中,我介绍过 Linux 用 systemd 来取代 init 作为系统的初始化进程.尽管这一改变引来了很多争议,但大多数发行版,包括 RedHa ...

  8. 动态ip服务器 动态ip服务器的常用连接方式 收藏版

    动态ip服务器目前比较常用的是VPS也叫作虚拟机.目前比较小型的vps服务器与普通电脑没什么区别,最大的区别就是用户连接zhidao服务器内的ip是固定不变的.而服务器运行的ip是可以动态的. 实现动 ...

  9. Vue3.0+ElementUI打包之后,为什么部分页面按钮图标找不到

    有的页面可以显示这个按钮,有的页面不可以,找了好久,看这都webpack路径问题,到但是我这个没有webpack,没有build文件夹,最后发现是因为没有绑定点击事件 加上这个之后就好了

  10. Alpha总结展望——前事不忘后事之师

    这个作业属于哪个课程 软件工程 这个作业要求在哪里 Alpha总结展望--前事不忘后事之师 这个作业的目标 Alpha总结展望 作业正文 正文 其他参考文献 无 一.个人感想总结 吴秋悦: 对Alph ...