题目

  点这里看题目。

分析

  我们不妨来考虑一下生成的序列有什么性质。
  为了方便表示,我们将序列 S S S的第 i i i项写为 S [ i ] S[i] S[i]。
  首先考虑如果所有的 A A A序列都是递增的,那么我们得到的序列肯定是递增的。如果存在递减的情况,例如其中某个序列 B ∈ { A 1 , A 2 , … , A n } B\in\{A_1,A_2,\dots,A_n\} B∈{A1​,A2​,…,An​},存在 B [ 1 ] > B [ 2 ] B[1]>B[2] B[1]>B[2]。那么按照取数规则,我们一旦取出了 B [ 1 ] B[1] B[1],我们就一定会取出 B [ 2 ] B[2] B[2]。这个比较显然。这是因为 B [ 1 ] B[1] B[1]被取出的时候,其他所有序列的第一个元素肯定都大于 B [ 1 ] B[1] B[1],因此也肯定大于 B [ 2 ] B[2] B[2]。
  我们发现只要序列中存在 B [ 1 ] > B [ 2 ] B[1]>B[2] B[1]>B[2]或者 B [ 2 ] > B [ 3 ] B[2]>B[3] B[2]>B[3],这两个数就会被相邻地取出;如果存在 B [ 1 ] > B [ 2 ] B[1]>B[2] B[1]>B[2]且 B [ 1 ] > B [ 3 ] B[1]>B[3] B[1]>B[3],这三个数也会被相邻取出。我们将这种必然相邻取出的情况分进一个组里面。
  注意到组只会有长度为 1 ,长度为 2 ,长度为 3 三种,而且由于一个长度为 2 的组一定和一个长度为 1 的组成对出现,因此长度为 2 的组的数量一定不超过长度为 1 的组的数量。
  我们可以发现,这样的组在构造的过程中,一定会按照组的第一个元素的大小进行排序构造出一个排列来。因此,一些组如果合法,就可以唯一确定一个排列。因此,我们可以通过计算组的合法构造方案来计算可生成的排列方案数。
  我们有两种方法来解决这个问题:

1.DP

  我们需要将 [ 1 , 3 n ] [1,3n] [1,3n]划分成若干组,限制如下:
   1. 每一组的长度不超过3。
   2. 每一组的第一个数一定是这一组中最大的。
   3. 长度为 2 的组的数量不超过长度为 1 的组的数量。
  因此我们可以设计如下的 DP 方案:
   f ( i , j ) f(i,j) f(i,j):前 i i i个数分组,满足长度为 1 的组的数量减去长度为 2 的组的数量为 j j j的方案数。
  转移实际上是考虑最后一个数会怎样分组。转移如下:
f ( i , j ) = f ( i − 1 , j − 1 ) + ( i − 1 ) f ( i − 2 , j + 1 ) + ( i − 1 ) ( i − 2 ) f ( i − 3 , j ) f(i,j)=f(i-1,j-1)+(i-1)f(i-2,j+1)+(i-1)(i-2)f(i-3,j) f(i,j)=f(i−1,j−1)+(i−1)f(i−2,j+1)+(i−1)(i−2)f(i−3,j)
  答案是 ∑ i = 0 3 n f ( 3 n , i ) \sum_{i=0}^{3n}f(3n,i) ∑i=03n​f(3n,i)。 DP 的时间是 O ( n 2 ) O(n^2) O(n2)。

2.枚举

  这其实是我自己口胡的。
  建议写第一种方法
  由于 n n n很小,我们可以直接枚举长度为 2 的组的数量和长度为 3 的组的数量(需要满足长度为 2 的组的数量不超过长度为 1 的数量这一前提)。设 f ( n ) f(n) f(n)为 2 n 2n 2n个数全部分为长度为 2 的组的方案数。转移大概如下:
f ( n ) = f ( n − 1 ) + ( 2 n − 2 ) ( 2 n − 3 ) f ( n − 2 ) f(n)=f(n-1)+(2n-2)(2n-3)f(n-2) f(n)=f(n−1)+(2n−2)(2n−3)f(n−2)
   g ( n ) g(n) g(n)为 3 n 3n 3n个数全部分为长度为 3 的组的方案数,转移类似。这样预处理完之后就可以枚举组的数量了。答案:
∑ i = 0 ⌊ 3 n 2 ⌋ ∑ j = 0 ⌊ 3 n − 2 i 3 ⌋ [ 3 n − 2 i − 3 j ≥ 2 i ] C 3 n 2 i × C 3 n − 2 i 3 j × f ( i ) × g ( j ) \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) i=0∑⌊23n​⌋​j=0∑⌊33n−2i​⌋​[3n−2i−3j≥2i]C3n2i​×C3n−2i3j​×f(i)×g(j)
  时间是 O ( n 2 ) O(n^2) O(n2)。
  如果有问题请轻喷,我也没有试过这个方法。

代码

#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] ); //长度为1if( j < t && i >= 2 ) add( f[i][j + t], 1ll * f[i - 2][j + t + 1] * ( i - 1 ) % M ); //长度为2if( 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-B]Merge Triplets相关推荐

  1. AtCoder AGC043D Merge Triplets (DP、组合计数)

    题目链接 https://atcoder.jp/contests/agc043/tasks/agc043_d 题解 考场上想到正确做法,然后思考实现细节的时候做法逐渐扭曲,最后GG--考后睡了一觉冷静 ...

  2. 『递推』[AGC043D] Merge Triplets

    P r o b l e m \mathrm{Problem} Problem 给定如下构造生成长度为 3 N 3N 3N 的排列 P P P 的方法: 先生成一个长度为 3 N 3N 3N 的排列 A ...

  3. GitHub 中 Merge pull request 的 3 中选项说明

    Merge pull request 提供了 3 种 merge 方法: Create a merge commit:GitHub 的底层操作是 git merge --no-ff.feature 分 ...

  4. Android布局优化之include、merge、ViewStub

    include:引入重复使用的相同布局 merge:减少include布局的层级,将子元素直接添加到merge标签的parent中 ViewStub:其实就是一个宽高都为0的一个View,它默认是不可 ...

  5. SQL 利用merge 同步数据库之间表的数据

    同步两个数据库之间两表的数据也许的数据库管理员偶尔需要做的一件事情,下面来记录一下常用的两种方法: 方法一:使用delete.truncate 方法二:使用 merge into  ,Merge是在S ...

  6. update 改写 merge into

    update语句改写成merge into有时会提高运行速度 看两个案例 1.根据业务将两个嵌套子查询改写成max,速度有3min提升到3s UPDATE OPER_792.LL_SCB_YDKB_2 ...

  7. 分离颜色通道(split)和多通道融合(merge)

    //通道的拆分 Mat srcImg=imread("1.jpg"); Mat ImgBChannel,ImgGChannel,ImgRChannel,mergeImg; vect ...

  8. LeetCode刷题记录15——21. Merge Two Sorted Lists(easy)

    LeetCode刷题记录15--21. Merge Two Sorted Lists(easy) 目录 LeetCode刷题记录15--21. Merge Two Sorted Lists(easy) ...

  9. Oracle中的MERGE语句

    转自http://blog.chinaunix.net/space.php?uid=16981447&do=blog&cuid=430716 做了简单的格式整理,加入了一点点原创的东西 ...

最新文章

  1. BAPI_CONTRACT_CREATE
  2. 【sprinb-boot】排除/不加载某些Bean
  3. 图像工程CH5:图像消噪和恢复
  4. ncut算法matlab实现,ncut_multiscale_1_6 经典的图像分割算法 的Matlab代码。 238万源代码下载- www.pudn.com...
  5. P4173-残缺的字符串【FFT】
  6. cmd 220 ftp 远程主机关闭连接_网络基础知识:FTP工作流程
  7. python3网络爬虫--爬取华为应用市场app数据(附源码)
  8. 辩证法——自然观、自然科学方法论和科学观
  9. Unity3D-人物角色选择
  10. 制作U盘引导盘,安装Ubuntu18.04系统
  11. 袋鼠云数据湖平台「DataLake」,存储全量数据,打造数字底座
  12. vue.js——ElementUI表单向后台提交FormData数据
  13. C Primer Plus(6) 中文版 第9章 函数 9.1 复习函数
  14. 30天免费试用 ▎(IDM) 极速下载工具
  15. 简报 | 井通公链实现商业应用真实用户数突破百万
  16. 若依框架客户管理按照创建时间字段排序报错解决方法
  17. 英特尔CPU工艺发展史
  18. 为什么黑客大牛都去腾讯?
  19. 【08月02日】A股滚动市盈率PE历史新低排名
  20. 入手中兴n880s电信定制手机及教你删除定制软件

热门文章

  1. wiki服务器网页地址,搭建个人wiki站点
  2. 编程入门之学哪种编程语言?
  3. PHP 连接sql server
  4. Ogre3D基础教程一
  5. Python爬取新冠肺炎疫情实时数据(丁香园)
  6. 16.WireShark学习-在WireShark中添加新协议
  7. 黑客是如何进行IP欺骗的
  8. 去除影像黑边-修改影像背景值-比Envi影像去除黑边-ArcGIS去除影像黑边-好用
  9. 解决Windows 10 无法访问指定设备、路径或文件
  10. ppt中的流程图怎么整体移动_如何快速在PPT中产生一个复杂的组织架构图?