NOIP2018提高组金牌训练营——动态规划专题

https://www.51nod.com/Live/LiveDescription.html#!#liveId=19

多重背包

二进制优化转化成01背包就好了

一只猪走进了一个森林。很凑巧的是,这个森林的形状是长方形的,有n行,m列组成。我们把这个长方形的行从上到下标记为1到n,列从左到右标记为1到m。处于第r行第c列的格子用(r,c)表示。

刚开始的时候猪站在(1,1),他的目标是走到(n,m)。由于猪回家心切,他在(r,c)的时候,只会往(r+1,c)或(r,c+1)走。他不能走出这个森林。

这只猪所在的森林是一个非同寻常的森林。有一些格子看起来非常相似,而有一些相差非常巨大。猪在行走的过程中喜欢拍下他经过的每一个格子的照片。一条路径被认为是漂亮的当且仅当拍下来的照片序列顺着看和反着看是一样的。也就是说,猪经过的路径要构成一个回文。

数一数从(1,1)到(n,m)有多少条漂亮路径。答案可能非常巨大,请输出对 $10^9+7$ 取余后的结果。

样例解释:有三种可能

  

收起

 

输入

单组测试数据。
第一行有两个整数 n,m (1≤n,m≤500),表示森林的长和宽。
接下来有n行,每行有m个小写字母,表示每一个格子的类型。同一种类型用同一个字母表示,不同的类型用不同的字母表示。

输出

输出答案占一行。

输入样例

3 4
aaab
baaa
abba

输出样例

3

注意到500分数据范围,考虑n三方的算法
发现回文非常难判断,可能要记录整个路径,不现实
所以从两端开始搜
f[x1][y1][x2][y2]表示从(1, 1)到(x1,y1),从(n, m)走到(x2, y2)
的方案数。这样就很好转移了,有四个方程,分别对应从(1, 1)往下还是往右
(n, m)往上还是往左
但是发现这样会炸空间,炸时间
那么显然有x1 + y1 = x2 + y2
那么f[x1][y1][x2]可以省去一维
但这样会炸空间
怎么办?
可以这样设计f[step][x1][x2], step = x1 + y1
有什么区别?
这样的话step的这一维只和step-1有关
所以可以用滚动数组优化掉一维的空间。
那么这道题就完美的解决了。
代码略……

1412 AVL树的种类

https://www.51nod.com/Challenge/Problem.html#!#problemId=1412&judgeId=0

平衡二叉树(AVL树),是指左右子树高度差至多为1的二叉树,并且该树的左右两个子树也均为AVL树。 现在问题来了,给定AVL树的节点个数n,求有多少种形态的AVL树恰好有n个节点。
 

输入

一行,包含一个整数n。 (0 < n <= 2000)

输出

一行表示结果,由于结果巨大,输出它对1000000007取余数的结果。

输入样例

10

输出样例

60

显然状态和节点数和高度有关,
设f[n][d]为有n个节点,高度为d的方案数
那么对于高度d,考虑左右子树,只存在与d-1与d-2两种情况
对于节点数n,可以枚举左右子树分别有多少,有i和n-i-1两种情况
那么转移的方程用到了乘法原理
dp[i][d]= dp[i - j - 1][d - 1] * dp[j][d - 1] + dp[i - j - 1][d - 1] * dp[j][d - 2] + dp[i - j - 1][d - 2] * dp[j][d - 1]
然后注意一些细节,见代码
#include<bits/stdc++.h>
#define add(a, b) a = (a + b) % MOD
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std; typedef long long ll;
const int MAXN = 2e3 + ;
const int MAXM = ;
const int MOD = ;
ll dp[MAXN][MAXM + ];
int n; int main()
{
scanf("%d", &n);
dp[][] = dp[][] = ; //注意这个初始化,特别注意空的节点
_for(i, , n)
_for(d, , MAXM) //深度最大也就十几左右
REP(j, , i) //最少0个,最多i-1个
{
add(dp[i][d], dp[i - j - ][d - ] * dp[j][d - ] % MOD);
add(dp[i][d], dp[i - j - ][d - ] * dp[j][d - ] % MOD);
add(dp[i][d], dp[i - j - ][d - ] * dp[j][d - ] % MOD);
} ll ans = ;
_for(d, , MAXM)
add(ans, dp[n][d]);
printf("%lld\n", ans); return ;
}
 
 
lyk最近计划按顺序做n道题目,每道题目都分为很多分数档次,lyk觉得这些题太简单了,于是它想到了一个好玩的游戏。

lyk决定将每道题目做出其中的某个分数,使得这n道题目的逆序对个数最多。
为了方便,假设共有m个分数档次,并且会给m个分数档次分配一个题目编号,表示该题目会出现这个分数档次。
题目保证每道题都存在至少一个分数档次。(例如样例中5道题目的分数分别是5,6,3,4,7,共有4个逆序对)

输入

第一行两个数n,m(n<=20,m<=100)。
接下来m行,每行一个数ai,表示第ai道题目可能会有i这个分数的档次。

输出

一个数表示最多逆序对个数。

输入样例

5 7
1
2
3
4
1
2
5

输出样例

4

n<=20
反应到状压dp
一般来说,逆序对是按照位置的顺序来求的
但是这道题要逆向思维,按照大小来求
因为题目输入的权值是递增的
所以只要判断在当前位置的后面有多少位置即可
但是这里要注意一点,我一开始用填表法去做,会WA
因为这里状态转移的时候涉及状态本身中1的个数,而有些状态是不合法的。
以前很多题可以用填表法是因为更新状态的时候用到的是状态中的某个位置,然后由位置导出权值,这样即使位置不合法,
导出权值的时候也会不合法而不会导致错解。但这道题就是用到状态本身,使得不合法的状态会导致错解
填表法就会把这些状态算进来。或者加个判断,判断之前的状态要是合法的,但是这显然没有刷表法方便
如果用到刷表法的话,就要注意初始化,起始状态初始化为0,其他为-1,表示不合法
然后转移的时候要判断当前状态合不合法
#include<bits/stdc++.h>
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std; int dp[( << ) + ], n, m; int main()
{
memset(dp, -, sizeof(dp));
dp[] = ;
scanf("%d%d", &n, &m);
_for(k, , m)
{
int x; scanf("%d", &x); x--;
REP(S, , << n)
if(dp[S] >= && !(S & ( << x)))
{
int sum = ;
REP(j, x + , n)
if(S & ( << j))
sum++;
dp[S | ( << x)] = max(dp[S | ( << x)], dp[S] + sum);
}
}
printf("%d\n", dp[( << n) - ]);
return ;
}

NOIP2018提高组金牌训练营——动态规划专题的更多相关文章

  1. NOIP2018提高组金牌训练营——搜索专题

    NOIP2018提高组金牌训练营——搜索专题 1416 两点 福克斯在玩一款手机解迷游戏,这个游戏叫做”两点”.基础级别的时候是在一个n×m单元上玩的.像这样: 每一个单元有包含一个有色点.我们将用不 ...

  2. NOIP2018提高组金牌训练营——字符串专题

    NOIP2018提高组金牌训练营——字符串专题 1154 回文串划分 有一个字符串S,求S最少可以被划分为多少个回文串. 例如:abbaabaa,有多种划分方式.   a|bb|aabaa - 3 个 ...

  3. NOIP2018提高组金牌训练营——数论专题

    地址 https://www.51nod.com/live/liveDescription.html#!liveId=23 1187 寻找分数 给出 a,b,c,d, 找一个分数p/q,使得a/b & ...

  4. [NOIp2018提高组]旅行

    [NOIp2018提高组]旅行: 题目大意: 一个\(n(n\le5000)\)个点,\(m(m\le n)\)条边的连通图.可以从任意一个点出发,前往任意一个相邻的未访问的结点,或沿着第一次来这个点 ...

  5. [NOIp2018提高组]赛道修建

    [NOIp2018提高组]赛道修建 题目大意: 给你一棵\(n(n\le5\times10^4)\)个结点的树,从中找出\(m\)个没有公共边的路径,使得第\(m\)长的路径最长.问第\(m\)长的路 ...

  6. [NOIp2018提高组]货币系统

    [NOIp2018提高组]货币系统 题目大意: 有\(n(n\le100)\)种不同的货币,每种货币的面额为\([1,25000]\)之间的一个整数.若两种货币系统能够组合出来的数是相同的的,那我们就 ...

  7. [NOIp2013提高组]积木大赛/[NOIp2018提高组]铺设道路

    [NOIp2013提高组]积木大赛/[NOIp2018提高组]铺设道路 题目大意: 对于长度为\(n(n\le10^5)\)的非负数列\(A\),每次可以选取一个区间\(-1\).问将数列清零至少需要 ...

  8. NOIP2018提高组省一冲奖班模测训练(六)

    NOIP2018提高组省一冲奖班模测训练(六) https://www.51nod.com/Contest/ContestDescription.html#!#contestId=80 20分钟AC掉 ...

  9. NOIP2018提高组省一冲奖班模测训练(五)

    NOIP2018提高组省一冲奖班模测训练(五) http://www.51nod.com/Contest/ContestDescription.html#!#contestId=79 今天有点浪…… ...

随机推荐

  1. STM32学习之路-LCD(4)&lt;显示字符&gt;

    昨晚疯狂的打了一夜的LOL,感觉L多了,今天一天精神萎靡.还是继续把显示字符给看了,可是在犹豫要不要写这篇文章 事实上写的东西也就是copy别人家的代码,不想写那么多,就记录下自己困惑的地方吧.也许改 ...

  2. [WPF]c#调用默认浏览器打开网址

    //调用系统默认的浏览器 System.Diagnostics.Process.Start("http://www.zhaokeli.com");

  3. 【待解决】maven创建web项目报错

    创建web项目时报错

  4. [ajax 学习笔记] ajax初试

    ajax全称是:asynchronous javasctipt and xml. 1.为什么须要ajax? 一般web程序与server的交互是:页面发送请求等待server处理,server处理数据 ...

  5. C++一些知识难点

    什么是"引用"?申明和使用"引用"要注意哪些问题? 答:引用就是某个目标变量的"别名"(alias).相应用的操作与对变量直接操作效果全然同 ...

  6. 301 和 302 对 SEO 的影响

    网站优化中,经常会面临网站链接修改或改变的事情,其中一个解决办法就是使用网站跳转的方式,处理变化的链接,下面讲述301和302跳转对SEO的影响. 301(永久移动) 请求的网页已被永久移动到新位置. ...

  7. luogu4012 深海机器人问题 网络流

    关键词:最小费用最大流 题目大意:海底是个网格,每个网格边有一定价值的海底化石.每个路线可经过无限个机器人,但上面的化石只能采一次.机器人可沿网格边向东或向北移动.给定机器人起点和终点位置及所能容纳的 ...

  8. [Javascript] 轻量级的JavaScript日期处理类库xDate使用指南

    XDate是一个请谅解的JavaScript的原生Date对象的封装库,提供增强的功能解析,格式化和日期处理.使用起来就和JavaScript自己的对象和方法一样,非常简单. XDate是一个请谅解的 ...

  9. IPv6通讯原理(1) - 不能忽略的网卡启动过程

    本文主题:通过抓包分析,深入观察网卡启动过程的每个步骤,从而逐步掌握通讯原理.

  10. VirtualBox里如何正确安装增强工具(图文详解)

    不多说,直接上干货! 找到 复制到