题目链接:传送门

题目:

题目描述

传说很久以前,大地上居住着一种神秘的生物:地精。

地精喜欢住在连绵不绝的山脉中。具体地说,一座长度为N的山脉H可分为从左到右的N段,每段有一个独一无二的高度Hi,其中Hi是1到N之间的正整数。

如果一段山脉比所有与它相邻的山脉都高,则这段山脉是一个山峰。位于边缘的山脉只有一段相邻的山脉,其他都有两段(即左边和右边)。

类似地,如果一段山脉比所有它相邻的山脉都低,则这段山脉是一个山谷。

地精们有一个共同的爱好——饮酒,酒馆可以设立在山谷之中。地精的酒馆不论白天黑夜总是人声鼎沸,地精美酒的香味可以飘到方圆数里的地方。

地精还是一种非常警觉的生物,他们在每座山峰上都可以设立瞭望台,并轮流担当瞭望工作,以确保在第一时间得知外敌的入侵。

地精们希望这N段山脉每段都可以修建瞭望台或酒馆的其中之一,只有满足这个条件的整座山脉才可能有地精居住。

现在你希望知道,长度为N的可能有地精居住的山脉有多少种。两座山脉A和B不同当且仅当存在一个i,使得Ai≠Bi。由于这个数目可能很大,你只对它除以P的余数感兴趣。

输入输出格式
输入格式: 输入文件goblin.in仅含一行,两个正整数N, P。 输出格式: 输出文件goblin.out仅含一行,一个非负整数,表示你所求的答案对P取余之后的结果。 输入输出样例 输入样例#: 输出样例#: 【数据规模和约定】 对于20%的数据,满足N≤; 对于40%的数据,满足N≤; 对于70%的数据,满足N≤; 对于100%的数据,满足3≤N≤,P≤1e9。

思路:又是似曾相识的那种dp。。分类讨论,转移方程显然。

如果在i之前的所有答案已经计算好了,那么更新i的时候就可以选择把i插入第k个和第k+1个之间,或者把i放在i-1个的旁边。

放置的时候因为i比之前的i-1个数都要大,所以它只能作为“山峰”出现,所以第k个和第k+1个必须都是山谷,放在旁边也是一样,相邻的必须是作为山谷的。

状态:

  f[i][0] 表示按题意放置好了i个数之后,左右两端都为山谷的方法数。

  f[i][1] 表示按题意放置好了i个数之后,左端山谷,右端山峰的方法数。

  f[i][2] 表示按题意放置好了i个数之后,左端山峰,右端山谷的方法数。

  f[i][3] 表示按题意放置好了i个数之后,左右两端都为山峰的方法数。

状态转移方程:

  f[i][0] += sum(f[j][0] * f[N-1-j][0] * Ci-1j);

  f[i][1] += sum(f[j][0] * f[N-1-j][1] * Ci-1j);

  f[i][2] += sum(f[j][2] * f[N-1-j][0] * Ci-1j);

  f[i][3] += sum(f[j][2] * f[N-1-j][1] * Ci-1j);

  N的范围是4500,其中的Ci-1j可以用杨辉三角跑出来,不过考虑到数据比较极限,可能会MLE,滚动数组优化之。

  据说可以扩展Lucas?。。。没学过赶紧去补(逃

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MAX_N = + ; ll N, P;
ll f[MAX_N][];//第二维:0低低,1低高,2高低,3高高
ll C[][MAX_N]; int main()
{
cin >> N >> P;
memset(f, , sizeof f);
C[][] = ;
C[][] = C[][] = ;
for (int i = ; i <= N; i++) {
if (i == )
f[i][] = , f[i][] %= P;
if (i > ) {//加在边界
f[i][] += f[i-][], f[i][] %= P;
f[i][] += f[i-][], f[i][] %= P;
f[i][] += f[i-][] + f[i-][], f[i][] %= P;
}
if (i >= ) for (int j = ; j <= i; j++)
C[i&][j] = (C[(i&)^][j-] + C[(i&)^][j]) % P;
for (int j = ; j < i-; j++) {//j >= 1 && i-1-j >= 1
ll cur = C[(i&)^][j];
f[i][] += (f[j][]*f[i--j][])%P*cur, f[i][] %= P;
f[i][] += (f[j][]*f[i--j][])%P*cur, f[i][] %= P;
f[i][] += (f[j][]*f[i--j][])%P*cur, f[i][] %= P;
f[i][] += (f[j][]*f[i--j][])%P*cur, f[i][] %= P;
}
}
ll ans = ;
for (int k = ; k <= ; k++) {
ans += f[N][k], ans %= P;
}
cout << (ans+P)%P << endl;
return ;
}

P2467 [SDOI2010]地精部落 (dp+组合数)【扩展Lucas好难不会】的更多相关文章

  1. P2467 [SDOI2010]地精部落 DP

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

  2. BZOJ 1925: [Sdoi2010]地精部落( dp )

    dp(i,j)表示1~i的排列中, 以1~j为开头且开头是下降的合法方案数 这种数列具有对称性, 即对于一个满足题意且开头是上升的n的排列{an}, 令bn = n-an+1, 那么{bn}就是一个满 ...

  3. Luogu P2467 [SDOI2010]地精部落 | 神奇的dp

    题目链接 DP 题目大意:给定一个数n,求1~n这n个整数的所有排列中有多少个波动数列,将这个数量%p后输出. 什么是波动数列呢?顾名思义,就是一个大.一个小.一个大.一个小--或者是一个小.一个大. ...

  4. [BZOJ1925][SDOI2010]地精部落(DP)

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

  5. P2467 [SDOI2010]地精部落

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

  6. luogu P2467 [SDOI2010]地精部落

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

  7. 【BZOJ】1925: [Sdoi2010]地精部落 DP+滚动数组

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1925 题意:输入一个数N(1 <= N <= 4200),问将这些数排列成折线 ...

  8. Luogu2467 SDOI2010 地精部落 DP

    传送门 一个与相对大小关系相关的$DP$ 设$f_{i,j,0/1}$表示放了$i$个,其中最后一个数字在$i$个中是第$j$大,且最后一个是极大值($1$)或极小值时($0$)的方案数.转移: $$ ...

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

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

随机推荐

  1. windows启动/禁用telnet/IIS/ftp/IE等服务

    将需要启动的钩选,将要禁用的取消钩选确定即可:比如我这里要启动telnet客户端. 启动IIS将IIS可承载的Web核心和Internet两大项全钩选上即可,钩多了不影响功能.

  2. valgrind 工具介绍和简单的使用

    最近老是遇上各种奇奇怪怪的core dump,不太会分析的情况下看到了这款工具.在这记录分享下. Valgrind 是个开源的工具,功能很多.例如检查内存泄漏工具---memcheck. Valgri ...

  3. 【Loadrunner_Http接口】使用Loadrunner对天气信息的接口编写脚本

    方法一:使用get请求 Action() { //http接口访问,get请求 web_url("www.abc.com", "URL=http://v.juhe.cn/ ...

  4. html <iframe>介绍

    iframe 元素会创建包含另外一个文档的内联框架 属性 值 描述 align left.right.top.middle.bottom 不赞成使用.请使用样式代替.规定如何根据周围的元素来对齐此框架 ...

  5. python 进程创建和共享内容的方法

    1.使用Pool来创建进程 from multiprocessing import Pool def f(n): return n*n if __name__=="__main__" ...

  6. poj3261

    题解: 同bzoj1717 代码: #include<bits/stdc++.h> using namespace std; ,P2=,P=; int a1[P],num[P],a2[P] ...

  7. 关于执行findbugs,checkstyle,jacoco插件检测代码,GitHook的脚本编写

    Git钩子的作用: (pre-commit ) 在用户执行 git commit -m "xxx" 命令之前,先执行pre-commit文件中的脚本命令 在pre-commit文件 ...

  8. docker pure-ftpd

    FROM alpine:3.7ADD http://dl-4.alpinelinux.org/alpine/edge/testing/x86_64/pure-ftpd-1.0.47-r0.apk /r ...

  9. Scrapy结构

    http://scrapy-chs.readthedocs.io/zh_CN/1.0/intro/overview.html scrapy 使用Twisted 这个异步网络库来处理网络通信,使用pyt ...

  10. 二. Python基础(2)--语法

    二. Python基础(2)--语法 1.实现一个简单的登录系统 '''# 形式1 n = 1 while n < 4:     name = input("请输入姓名\n" ...