题目链接

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的更多相关文章

  1. luogu P2467 [SDOI2010]地精部落

    很有意思的dp计数题目. 思考一下发现开始时山峰和开始是山谷的方案数是相同的 所以我们只需要统计一个即可. 证明的话可以考虑对于任意一种开始时山峰的方案 每个数字变成n-a[i]+1 那么可以此方案还 ...

  2. 【ybt金牌导航1-2-6】【luogu P2467】地精部落

    地精部落 题目链接:ybt金牌导航1-2-6 / luogu P2467 题目大意 有一个排列,要使得每个位置要么都比两边高,要么比两边低. 而且一定要以一高一低的方式排列. 两边的只用比旁边的那个高 ...

  3. P2467 [SDOI2010]地精部落 DP

    传送门:https://www.luogu.org/problemnew/show/P2467 参考与学习:https://www.luogu.org/blog/user55639/solution- ...

  4. P2467 [SDOI2010]地精部落 (dp+组合数)【扩展Lucas好难不会】

    题目链接:传送门 题目: 题目描述 传说很久以前,大地上居住着一种神秘的生物:地精. 地精喜欢住在连绵不绝的山脉中.具体地说,一座长度为N的山脉H可分为从左到右的N段,每段有一个独一无二的高度Hi,其 ...

  5. Luogu 2467[SDOI2010]地精部落 - DP

    Solution 这题真秒啊,我眼瞎没有看到这是个排列 很显然, 有一条性质: 第一个是山峰 和 第一个是山谷的情况是一一对应的, 只需要把每个数 $x$  变成 $n-x+1$ 然后窝萌定义数组 $ ...

  6. P2467 [SDOI2010]地精部落

    题目描述 传说很久以前,大地上居住着一种神秘的生物:地精. 地精喜欢住在连绵不绝的山脉中.具体地说,一座长度为N的山脉H可分为从左到右的N段,每段有一个独一无二的高度Hi,其中Hi是1到N之间的正整数 ...

  7. 洛咕 P2467 [SDOI2010]地精部落

    同波浪,简单dp. 高度从1到n插入山脉,设f[i][j][k]表示插入了i个山脉,组成了j段,边界上有k个山脉的方案数. 那么新插入的山脉只会:插入在边界上且自己是一段.插入在边界上且与最左边的段相 ...

  8. 洛谷 P2467 [SDOI2010]地精部落

    洛谷 我讲的应该没有这个[https://www.luogu.org/blog/user55639/solution-p2467]清楚. 贴个代码算了: #include <bits/stdc+ ...

  9. Luogu 2467 [SDOI2010]地精部落

    挺有意思的题. 优质题解: https://www.luogu.org/blog/user55639/solution-p2467 题意为求长度为n,取值为$[1, n]$的波动序列的个数. 首先需要 ...

随机推荐

  1. .NET 6 中的HTTP 3支持

    dotnet团队官方博客发布了一篇HTTP3的文章:HTTP/3 support in .NET 6:https://devblogs.microsoft.com/dotnet/http-3-supp ...

  2. PHP的另一个高效缓存扩展:Yac

    之前的文章中我们已经学习过一个 PHP 自带的扩展缓存 Apc ,今天我们来学习另一个缓存扩展:Yac . 什么是 Yac 从名字其实就能看出,这又是鸟哥大神的作品.毕竟是 PHP 的核心开发人员,他 ...

  3. DEDECMS首页循环调用一级栏目和二级栏目的实现方法

    调用方法: {dede:channelartlist typeid='2'} <li class="First"><a href="{dede:fiel ...

  4. jmeter跑脚本的注意事项

    指标主要看以下几点: 1.jmeter性能测试的报告,不要看平均响应时间,而是看90%响应时间,一般不能超过3s,超过3s则不符合标准2.响应时间超过3s就要优化,但不是平均响应时间,因为最小响应时间 ...

  5. centos虚拟机中挂新硬盘

    配置一台centos7,主硬盘20G装系统:副硬盘20G作为数据盘(格式:XFS)挂载到根目录:/vdir/ ,XFS是高性能文件系统. 外层vm硬盘添加好后,执行下面 1.fdisk -l //查看 ...

  6. 【Azure Developer】Azure Automation 自动化账号生成的时候怎么生成连接 与证书 (Connection & Certificate)

    Azure Automation :The Azure Automation service provides a highly reliable and scalable workflow exec ...

  7. 【深度学习】线性回归(Linear Regression)——原理、均方损失、小批量随机梯度下降

    1. 线性回归 回归(regression)问题指一类为一个或多个自变量与因变量之间关系建模的方法,通常用来表示输入和输出之间的关系. 机器学习领域中多数问题都与预测相关,当我们想预测一个数值时,就会 ...

  8. Maccms8.x(苹果cms)命令执行漏洞

    getshell payload(a): http://0-sec.org/index.php?m=vod-search&wd={if-A:assert($_POST[a])}{endif-A ...

  9. 从零入门 Serverless | 企业级 CI/CD 工具部署 Serverless 应用的落地实践

    背景知识 通过以往几节课程的学习,相信大家对于 SAE 平台已经有了一定的了解.SAE 为客户免除了很多复杂的运维工作,开箱即用.按用量付费:与此同时 SAE 提供了丰富的 Open API,可以很容 ...

  10. 使用tinypng对需要上传Gitee图床的图片进行压缩

    目录 背景 Tinypng简介 Tinypng使用 手动上传图片 使用API 调用API自动上传超过1MB图片 安装tinyfy 自动上传脚本 其他 背景 在使用Gitee作为图床时(使用Typora ...