题目

  点这里看题目。

分析

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

  为了方便表示,我们将序列\(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. mysql小白系列_11 MHA

    一.MHA是什么?能干什么的 (1)以Perl语言写的一套Mysql故障切换方案,一个脚本管理工具 (2)保障数据库的高可用性 (3)修复多个slave之间的差异日志,最终使所有的slave保持数据一 ...

  2. Java——多线程基础知识

    多线程进程和线程的区别:每一个进程拥有自己的一整套变量,而线程则共享数据.java.lang.Thread    static void sleep(long millis) 线程休眠给定的毫秒数,用 ...

  3. Java 泛型与集合

    1.List练习,请用泛型的写法来完成. 已知有一个Worker 类如下: public class Worker  { private int age; private String name; p ...

  4. Java 14 祭出代码简化大器,Lombok 要被干掉了?

    Java 14 3 月发布距现在已经发布 2 个多月,发布了很多新特性,详细的新特性介绍可以看这篇文章: http://www.javastack.cn/article/2020/java14-has ...

  5. 【转】最长公共子序列(LCS),求LCS长度和打印输出LCS

    求LCS的长度,Java版本: public static int LCS(int[]a,int[] b) { int [][]c=new int[a.length+1][b.length+1]; f ...

  6. Weblogic 漏洞利用总结

    整理的一些利用方式,后续会更新到15年至今的洞 后台爆破拿shell 后台爆破: 部署-安装-上载文件 制作war包,一直下一步,最好保存 jar -cvf shell.war ./shll/* 上传 ...

  7. 13 . Python3之并发编程

    什么是操作系统? 为什么要有操作系统? 现代的计算机系统主要是由一个或者多个处理器,主存,硬盘,键盘,鼠标,显示器,打印机,网络接口及其他输入输出设备组成. 一般而言,现代计算机系统是一个复杂的系统. ...

  8. Rocket - diplomacy - DUEB参数模型的设计

    https://mp.weixin.qq.com/s/9PEEpe1pkQDN9RWpOGSUCQ   介绍DUEB参数模型的设计,不包含实现(实现对设计做了简化).     1. DUEB   di ...

  9. 重学 Java 设计模式:实战适配器模式

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 擦屁屁纸80%的面积都是保护手的! 工作到3年左右很大一部分程序员都想提升自己的技术 ...

  10. Spring-boot01

    本文记录Spring-Boot学习途中的点点滴滴. 其实Spring-Boot出来好长时间了,但是一直没去关注过.之前在我的印象里Spring-Boot好就好在减去了很多XML配置,加入了很多自动配置 ...