题目链接

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. Docker入门系列之一:什么是Docker?

    原文作者:Jeff Hale 原文地址:https://towardsdatascience.com/learn-enough-docker-to-be-useful-b7ba70caeb4b 翻译: ...

  2. webpack线上和线下模式

    区别: 1 线下模式代码没有压缩,source-map是全的,比较容易定位错误,调试方便 2 线上模式的代码是压缩的,文件小, 分开打包: 方式一:有点麻烦 在package.json文件 " ...

  3. Java基础系列(37)- 数组下标越界及小结

    数组的四个基本特点 其长度是确定的,数组一旦被创建,它的大小就是不可以改变的 其元素必须是相同类型,不允许出现混合类型 数组中的元素可以是任何数据类型,包括基本类型和引用类型 数组变量属于引用类型,数 ...

  4. Jmeter系列(30)- 性能指标(3) | 性能指标峰值

    性能指标峰值 简述 彻底理解了性能指标(1)(2)的内容,这一篇随笔其实就不用看了,而且大家也能猜到这一篇内容是啥:二八原则 性能指标不要硬性的往那些性能指标上去靠,要根据业务来,熟悉业务,明白了解你 ...

  5. mac使用brew update无反应,更新慢解决办法

    一.原因 主要是资源访问太慢的原因造成的,替换一下镜像就可以了 有点耐心,大概5分钟就可以了,刚开始的时候terminal 只有顶部的title栏会变化,最后才会出现更新结果 使用中科大的镜像 替换默 ...

  6. mysql从零开始之MySQL 删除数据库

    MySQL 删除数据库 使用普通用户登陆 MySQL 服务器,你可能需要特定的权限来创建或者删除 MySQL 数据库,所以我们这边使用 root 用户登录,root 用户拥有最高权限. 在删除数据库过 ...

  7. 关于django配置好静态文件后打开相关图片页显示404的解决方法

    在url里设置以上代码即可,即可解决图片显示异常(出现此问题的根本原因是django版本)django3后需要加以上代码)

  8. Java基础之(十一):方法

    Java方法详解 何谓方法(了解) System.out.println() // 类 对象 方法 方法是语句的集合,它们在一起执行一个功能. 方法是解决一类问题的步骤的有序集合 方法包含于类或对象中 ...

  9. 【NOIP1998】 三连击 题解

    文章转载前需和原作者联系,否则追究法律责任 题目链接:https://www.luogu.com.cn/problem/P1008 首先我们来分析一下题目.要求是枚举三个数,比例为1:2:3,且各个数 ...

  10. EPUB文件格式简单解析

    最近热衷于看轻小说,奈何某些网站样式排版属实糟糕,移动端体验极度不友好,实在无法忍受,于是希望能将网站内容爬取下来制作成EPUB格式的电子书. 抛开爬取网站内容不谈,通过解析EPUB文件后,大致掌握了 ...