Luogu P2467 [SDOI2010]地精部落 | 神奇的dp
DP
题目大意:给定一个数n,求1~n这n个整数的所有排列中有多少个波动数列,将这个数量%p后输出。
什么是波动数列呢?顾名思义,就是一个大、一个小、一个大、一个小……或者是一个小、一个大、一个小、一个大……像“5,2 ,3,1,4”和“2,3,1,5,4”这样的数列就叫做波动数列,题目里也很形象地说了。
首先,关于波动数列,我们可以推出两条性质:
性质一:在一个波动数列中,若一个数x与另一个数(x+1)不相邻,那么交换这两个数的位置就可以得出一个新的波动数列。
例子:波动数列“1,3,2,5,4”中的“1”与“2”不相邻,那么交换“1”与“2”的位置就可以得出新的波动数列“2,3,1,5,4”。
证明:对于符合这个性质的波动数列我们可以这样表示:{...... a,x,b,......,c,(x+1),d,.......}(省略号表示的是数列中的其它数),那么有四种情况:
情况一:当x为山谷,(x+1)也为山谷时,a>x,b>x,c>x+1,d>x+1。
①因为此题中的波动数列没有重复的数,所以a!=x+1,b!=x+1,所以a>x+1,b>x+1,所以当(x+1)移动到x的位置后不会破坏波动数列。
②因为c>x+1,d>x+1,所以c>x,d>x,所以当x移动到(x+1)的位置后不会破坏波动数列。
情况二:当x为山峰,(x+1)为山谷时,a<x,b<x,c>x+1,d>x+1。
①因为a<x,b<x,所以a<x+1,b<x+1,所以当(x+1)移动到x的位置后不会破坏波动数列。
②同情况一第②条
情况三:当x为山谷,(x+1)为山峰时,a>x,b>x,c<x+1,d<x+1。
①同情况一第①条。
②因为此题中的波动数列没有重复的数,所以c!=x,d!=x,所以c<x,d<x,所以当x移动到(x+1)的位置后不会破坏波动数列。
情况四:当x为山峰,(x+1)也为山峰时,a<x,b<x,c<x+1,d<x+1。
①同情况二第①条。
②同情况三第②条。
综上所述,将x与(x+1)在数列中的位置交换后可得出新的波动数列。
性质二:在一个为n的波动数列中,将每个数x都变成(n-x+1)就可以得出一个新的波动数列。
例子:波动数列“3,2,4,1”按上述步骤操作后可变成新波动数列“2,3,1,4”。
证明:这个操作其实就是把最大的数变成最小的数,最小的数变成最大的数,次大的数变成次小的数,次小的数变成次大的数……假如有这样一个山峰: a,b,c,其中a<b,c<b,那么它变形后就是这样子的:n-a+1,n-b+1,n-c+1。将变形后的三个数同时减去(n+1),即可得出-a,-b,-c,由a<b,c<b可知-a>-b,-c>-b,又因为变形后的三个数同时减去同一个数后大小关系是不变的,所以可得n-a+1>n-b+1,n-c+1>n-b+1。我们可以发现,山峰变成了山谷,但这并没有破坏波动数列,所以这是没有影响的。如果这变形之前是一个山谷也是一样的道理,大家可以自己动脑想一下。综上所属,将一个波动数列按性质二中的步骤操作后可以得出一个新的波动数列。
知道了这三条性质之后,我们就能用动态规划来解决这一问题了,状态就是f[i][j],这表示前i个数,以j为开头且j为山峰时的方案数。为什么只考虑开头为山峰时的方案数呢?因为根据性质二,将开头为山峰的、长度为n的波动数列中的每个数x都变成(n-x+1)后就是一个开头为山谷的波动数列了(证明中有写到),所以我们最后只要将开头为山峰的方案数乘2就好了。
有了状态之后,剩下的问题就是如何转移了,这里我先给出状态转移方程吧,如下:
f[i][j]=f[i][j-1]+f[i-1][i-j+1]
思路:对于状态转移,我们考虑从(j-1)转移过来。那么这里就有两种情况,一种是j与(j-1)不相邻,另一种是j与(j-1)相邻。
j与(j-1)不相邻的情况很好处理,因为根据性质一,若(j-1)与j不相邻,那么交换(j-1)与j的位置即可得出一个新的波动数列,所以这一种情况的方案数即为f[i][j-1]。有人可能会问,如果f[i][j-1]中包含了(j-1)与j相邻的情况怎么办?这样一交换不就错了吗?这一种情况是不可能出现的,因为f[i][j-1]是表示前i个数中以(j-1)为开头且(j-1)为山峰的方案数,那么与(j-1)相邻的只能是第二个数且第二个数一定比(j-1)要小,而j又比(j-1)要大,所以在f[i][j-1]所包含的方案中j是不会与(j-1)相邻的。
j与(j-1)相邻的情况其实也不太难想,大家请想一想,此时(j-1)紧紧地跟在j后面,这不就变成了求有i个数,(j-1)为开头且(j-1)为山谷的方案数吗?但这与我们所设立的状态表示的意义不同怎么办?没关系的,我们可以把它变一变。j后面的数都在[1,j-1]和[j+1,i]这两个区间内,一共有(i-1)个数。我们可以将[j+1,i]这个区间内的数全部减去1,就变成了[j,i-1],再与前一个区间合并一下,变成[1,i-1],这样减是不会改变数之间的相对的大小关系的,所以方案数也不会变。但此时的开头(j-1)仍是山谷啊,没错,但根据性质二,将开头为山谷的波动数列按性质中的步骤操作一番就变成开头为山峰的波动数列啦,反过来也一样。那么,我们只要求出以[(i-1)-(j-1)+1]为开头且为山峰的方案数就好了(再反一次就变回以(j-1)为开头且为山谷的方案数了嘛)。所以,这一种情况的方案数即为f[i-1][(i-1)][(i-1)-(j-1)+1],化简后就是f[i-1][i-j+1]。
综上所述,状态转移方程即为f[i][j]=f[i][j-1]+f[i-1][i-j+1]。
最后,极短的代码奉上:
#include<iostream>
#include<cstdio>
using namespace std;
int f[4205][4205];
int main()
{
int n=0,p=0,ans=0;
scanf("%d%d",&n,&p);
f[1][1]=1;//初始化
for(int i=2;i<=n;i++)
for(int j=2;j<=i;j++)//1是不可能做为山峰的,所以从2开始枚举
f[i][j]=(f[i][j-1]+f[i-1][i-j+1])%p;
for(int i=1;i<=n;i++) ans=(ans+f[n][i])%p;
printf("%d",(ans*2)%p);
return 0;
}
参考文章:https://www.luogu.org/blog/user55639/solution-p2467
Luogu P2467 [SDOI2010]地精部落 | 神奇的dp的更多相关文章
- luogu P2467 [SDOI2010]地精部落
很有意思的dp计数题目. 思考一下发现开始时山峰和开始是山谷的方案数是相同的 所以我们只需要统计一个即可. 证明的话可以考虑对于任意一种开始时山峰的方案 每个数字变成n-a[i]+1 那么可以此方案还 ...
- 【ybt金牌导航1-2-6】【luogu P2467】地精部落
地精部落 题目链接:ybt金牌导航1-2-6 / luogu P2467 题目大意 有一个排列,要使得每个位置要么都比两边高,要么比两边低. 而且一定要以一高一低的方式排列. 两边的只用比旁边的那个高 ...
- P2467 [SDOI2010]地精部落 DP
传送门:https://www.luogu.org/problemnew/show/P2467 参考与学习:https://www.luogu.org/blog/user55639/solution- ...
- P2467 [SDOI2010]地精部落 (dp+组合数)【扩展Lucas好难不会】
题目链接:传送门 题目: 题目描述 传说很久以前,大地上居住着一种神秘的生物:地精. 地精喜欢住在连绵不绝的山脉中.具体地说,一座长度为N的山脉H可分为从左到右的N段,每段有一个独一无二的高度Hi,其 ...
- Luogu 2467[SDOI2010]地精部落 - DP
Solution 这题真秒啊,我眼瞎没有看到这是个排列 很显然, 有一条性质: 第一个是山峰 和 第一个是山谷的情况是一一对应的, 只需要把每个数 $x$ 变成 $n-x+1$ 然后窝萌定义数组 $ ...
- P2467 [SDOI2010]地精部落
题目描述 传说很久以前,大地上居住着一种神秘的生物:地精. 地精喜欢住在连绵不绝的山脉中.具体地说,一座长度为N的山脉H可分为从左到右的N段,每段有一个独一无二的高度Hi,其中Hi是1到N之间的正整数 ...
- 洛咕 P2467 [SDOI2010]地精部落
同波浪,简单dp. 高度从1到n插入山脉,设f[i][j][k]表示插入了i个山脉,组成了j段,边界上有k个山脉的方案数. 那么新插入的山脉只会:插入在边界上且自己是一段.插入在边界上且与最左边的段相 ...
- 洛谷 P2467 [SDOI2010]地精部落
洛谷 我讲的应该没有这个[https://www.luogu.org/blog/user55639/solution-p2467]清楚. 贴个代码算了: #include <bits/stdc+ ...
- Luogu 2467 [SDOI2010]地精部落
挺有意思的题. 优质题解: https://www.luogu.org/blog/user55639/solution-p2467 题意为求长度为n,取值为$[1, n]$的波动序列的个数. 首先需要 ...
随机推荐
- DFS与DFS迷宫问题
一天蒜头君掉进了一个迷宫里面,蒜头君想逃出去,可怜的蒜头君连迷宫是否有能逃出去的路都不知道. 看在蒜头君这么可怜的份上,就请聪明的你告诉蒜头君是否有可以逃出去的路. 输入格式 第一行输入两个整数n 和 ...
- 洛谷P1094——纪念品分组(简单贪心)
https://www.luogu.org/problem/show?pid=1094 题目描述 元旦快到了,校学生会让乐乐负责新年晚会的纪念品发放工作.为使得参加晚会的同学所获得 的纪念品价值相对均 ...
- PHP的zlib压缩工具扩展包学习
总算到了我们压缩相关扩展的最后一篇文章了,最后我们要学习的也是 Linux 下非常常用的一种压缩格式:.gz 的压缩扩展.作为 PHP 的自带扩展,就像 zip 一样,zlib 扩展是随着 PHP 的 ...
- Java基础系列(12)- 运算符
运算符 算数运算符:+ - * / % ++ -- 赋值运算符:= += -= *= /= 关系运算符:> < >= <= == != instanceof 逻辑运算符:&am ...
- Docker 配置国内镜像加速器
Docker 默认是从官方镜像地址 Docker Hub 下下载镜像,由于服务器在国外的缘故,导致经常下载速度非常慢.为了提升镜像的下载速度,我们可以手动配置国内镜像加速器,让下载速度飚起来. 国内的 ...
- 解决navicat 导出excel数字为科学计数法问题
1.原因分析 用程序导出的csv文件,当字段中有比较长的数字字段存在时,在用excel软件查看csv文件时就会变成科学技术法的表现形式. 其实这个问题跟用什么语言导出csv文件没有关 ...
- Python Type Hints(类型提示)
在做自动化测试的时候,改进测试框架,类型提示会让你写代码时更加流程,当你在一个模块定义了类型,而其他模块没有提示的时候,是相当不方便.
- WPF进阶技巧和实战03-控件(2-特殊容器)
ScrollViewer控件 直接继承ContextControl类,提供了虚拟界面,允许用户围绕更大的元素滚动.只能包含单个元素(ContextControl决定),但可以放置布局控件来实现多个任意 ...
- Linux安装配置Java
先从 Oracle 官网下载 Java 运行 tar -zxvf xxxx.tar.gz 指令将 Java 解压到 /usr/local/java 下(个人习惯,无所谓) 修改环境变量 vim /et ...
- Serverless 对研发效能的变革和创新
作者 | 杨皓然(不瞋) 对企业而言,Serverless 架构有着巨大的应用潜力.随着云产品的完善,产品的集成和被集成能力的加强,软件交付流程自动化能力的提高,我们相信在 Serverless 架构 ...