[AGC043-D]Merge Triplets
题目
点这里看题目。
分析
我们不妨来考虑一下生成的序列有什么性质。
为了方便表示,我们将序列\(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\)的方案数。
转移实际上是考虑最后一个数会怎样分组。转移如下:
\]
答案是\(\sum_{i=0}^{3n}f(3n,i)\)。DP 的时间是\(O(n^2)\)。
2.枚举
这其实是我自己口胡的。
建议写第一种方法。
由于\(n\)很小,我们可以直接枚举长度为 2 的组的数量和长度为 3 的组的数量(需要满足长度为 2 的组的数量不超过长度为 1 的数量这一前提)。设\(f(n)\)为\(2n\)个数全部分为长度为 2 的组的方案数。转移大概如下:
\]
\(g(n)\)为\(3n\)个数全部分为长度为 3 的组的方案数,转移类似。这样预处理完之后就可以枚举组的数量了。答案:
\]
时间是\(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的更多相关文章
- AT5801 [AGC043D] Merge Triplets
这种排列生成排列的题目我们一般可以考虑生成排列合法的充要条件. 首先可以发现的一点就是该生成排列的任意一个数 \(p_i\) 一定不存在连续的三个数 \(p_{i + 1}, p_{i + 2}, p ...
- [算法]——归并排序(Merge Sort)
归并排序(Merge Sort)与快速排序思想类似:将待排序数据分成两部分,继续将两个子部分进行递归的归并排序:然后将已经有序的两个子部分进行合并,最终完成排序.其时间复杂度与快速排序均为O(nlog ...
- SQL 提示介绍 hash/merge/concat union
查询提示一直是个很有争议的东西,因为他影响了sql server 自己选择执行计划.很多人在问是否应该使用查询提示的时候一般会被告知慎用或不要使用...但是个人认为善用提示在不修改语句的条件下,是常用 ...
- Merge Sorted Array
Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array. Note:Yo ...
- SQL Tuning 基础概述06 - 表的关联方式:Nested Loops Join,Merge Sort Join & Hash Join
nested loops join(嵌套循环) 驱动表返回几条结果集,被驱动表访问多少次,有驱动顺序,无须排序,无任何限制. 驱动表限制条件有索引,被驱动表连接条件有索引. hints:use_n ...
- Git 少用 Pull 多用 Fetch 和 Merge
本文有点长而且有点乱,但就像Mark Twain Blaise Pascal的笑话里说的那样:我没有时间让它更短些.在Git的邮件列表里有很多关于本文的讨论,我会尽量把其中相关的观点列在下面. 我最常 ...
- Merge 的小技巧
今天跟大家分享一下搬动数据使用Merge的方法. 有些时候,当我们做数据搬动的时候,有时候做测试啊,换对象啊,就会存在有时候外键存在,不知道怎么对应的关系.比如我现在有架构相同的两组table , A ...
- [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 ...
- [LeetCode] Merge Intervals 合并区间
Given a collection of intervals, merge all overlapping intervals. For example, Given [1,3],[2,6],[8, ...
随机推荐
- poj1699 KMP+壮压DP
Best Sequence Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 6338 Accepted: 2461 Des ...
- Centos慢慢长大(一)
1.写在前面 这将是一个系列性的文章.可能更多的是记录我在学习的过程中的一些感悟吧.我想强调的是在这一系列文章里我会从最小化的安装开始,然后逐渐的增加需要安装的软件.就象一个婴儿的诞生,慢慢的学走路. ...
- hide handkerchief(hdu2104)
思考:这种找手绢就是,在判断是否互质.用辗转相除法(用来求最大公约数:a)进行判断.r=a%b;a=b;b=r;循环限制条件:除数b=0是结束除法.如果这时被除数a=1,则表示两个互质. #inclu ...
- pyenv,轻松切换各种python版本
pyenv,轻松切换各种python版本 解决什么问题 mac自带python2,md又不能删掉他 linux也自带python2,这玩意都过时了,也不赶紧换掉 安装pyenv git 安装 git ...
- VMware虚拟机,vps忘记密码修改密码
因为业务经常会用到虚拟机,然后过不了多久,登录密码就用不了. 解决问题有两种办法,其中一种是通过Dos命令窗:还有一个就是通过制作pe启动盘来操作,进行密码重置,删除等等. 制作pe启动盘的方式有 ...
- 蒲公英 · JELLY技术周刊 Vol.08 -- 技术周刊 · npm install -g typescript@3.9.3
登高远眺 沧海拾遗,积跬步以至千里 基础技术 官宣: Typescript 3.9 正式发布 TypeScript 3.9 正式发布,这个版本主要聚焦于性能.改进某些特性和提升稳定性.编译器效率在这一 ...
- JavaScript中foreach、map、filter、find、every、some的用法
foreach:只是循环数组中的每一项,没有返回值 如: var arr = [2,3,3,4,5,6]; arr.foreach(function(item,index,array){ dosom ...
- [软件版本贴]SD.TEAM软件集
手机轰炸机-版本:v1.0.下载地址:http://pan.baidu.com/1.zip! 营销软件盒-版本:v1.0.下载地址:http://pan.baidu.com/2.zip! 不加群提取群 ...
- C/C++多参数函数参数的计算顺序与压栈顺序
一.前言 今天在看Thinking in C++这本书时,书中的一个例子引起了我的注意,具体是使用了下面这句 单看这条语句的语义会发现仅仅是使用一个简单的string的substr函数将所得子串pus ...
- Beta冲刺——测试随笔
这个作业属于哪个课程 软件工程 这个作业要求在哪里 团队作业第五次--Beta冲刺 这个作业的目标 Beta冲刺 作业正文 正文 github链接 项目地址 其他参考文献 无 一.测试工作安排 项目 ...