HDU 5693 D Game(区间dp)
来源:互联网 发布:推荐好看的小说知乎 编辑:程序博客网 时间:2024/05/29 15:53
原题链接
题目描述
Problem Description
众所周知,度度熊喜欢的字符只有两个:B 和D。
今天,它发明了一个游戏:D游戏。
度度熊的英文并不是很高明,所以这里的D,没什么高深的含义,只是代指等差数列(等差数列百科)中的公差D。
这个游戏是这样的,首先度度熊拥有一个公差集合{D},然后它依次写下N个数字排成一行。游戏规则很简单:
在当前剩下的有序数组中选择X(X≥2) 个连续数字;
检查1选择的X个数字是否构成等差数列,且公差 d∈{D};
如果2满足,可以在数组中删除这X个数字;
重复 1−3 步,直到无法删除更多数字。
度度熊最多能删掉多少个数字,如果它足够聪明的话?
Input
第一行一个整数T,表示T(1≤T≤100) 组数据。
每组数据以两个整数 N,M 开始 。接着的一行包括 N 个整数,表示排成一行的有序数组 Ai。接下来的一行是 M 个整数,即给定的公差集合 Di。
1≤N,M≤300
−1 000 000 000≤Ai,Di≤1 000 000 000
Output
对于每组数据,输出最多能删掉的数字 。
题目分析
第一次看见这个题的时候,笔者也是一头雾水,不知从何下手。回顾题目,对于每组数据,求最多能删除多少数字。看到数组,我们可以自然的想到子数组,求子数组最多能删掉数字是和原问题等价的问题。这个时候,我们能联想到贪心和DP。
“求子数组最多能删掉多少数字?” 是原问题的最优子结构吗?可以试着举举反例
现在,我们来看看动态规划的方法。原问题求数组a[1…N]最多能删掉多少数字?现在,我们考虑字数组a[i…j]最多能删掉多少数字?
dp[l][r] : 从l到r能删掉的最多数字。
c[i][j]: a[i], a[j]构成等差数列(a[j] - a[i] 属于集合D)。
我们采用这样一种思路:看a[l…r]首尾两个数字能否和a[l..r]中间的数字构成等差数列,进而把a[l..r]再拆分成更小的字数组,达到动态转移的目的。
共有以下几种情况:
- a[l], a[r]构成等差数列(可以删除),且中间所有的数都能删除。c[l][r] == 1 && dp[l+1][r-1] == r - l - 1;
- a[l], a[j](l < j < r)构成等差数列。且两个数中间的数都能删除。c[l][j] == 1 && dp[l+1][j-1] == j - l - 1;
- a[r], a[j](l < j < r)构成等差数列。且两个数中间的数都能删除。c[j][r] == 1 && dp[j+1][r-1] == r - j - 1;
- a[l], a[j], a[r](l < j < r)构成等差数列。三个数之间的数都能被删除。c[l][j] == 1 && c[j][r] == 1 && a[r] - a[j] == a[j] - a[i] && dp[l+1][j-1] == j - l -1 && dp[j+1][r-1] == r - j -1;
如果不满足上诉四种情况,说明a[l…r]中的a[l], a[r]不能和中间的数建立练习(构成等差数列)。这个时候,我们有:
- dp[l][r] == max(dp[l+1][r], dp[l][r-1])
- dp[l][r] == max(dp[l][j] + dp[j+1][r]) , l < j < r-1
因为最后是求a[1…N]最多能删掉多少数字, 则不管上述四种情况是否满足,这两种情况都应该计算在内。
AC代码
#include <iostream>#include <cstring>using namespace std;int c[305][305], dp[305][305];int a[305];int main(){ int t, n, m, tmp; scanf("%d", &t); while(t--){ memset(dp, 0, sizeof(dp)); memset(c, 0, sizeof(c)); scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) scanf("%d", &a[i]); for(int i = 1; i <= m; i++){ scanf("%d", &tmp); for(int j = 1; j <= n-1; j++) { for(int k = j+1; k <= n; k++) { if(a[k] - a[j] == tmp) c[j][k] = 1; } } } for(int k = 1; k <= n-1; ++k) { for(int l = 1; l+k <= n; l++) { int r = l+k; dp[l][r] = max(dp[l+1][r], dp[l][r-1]); if(c[l][r] == 1 && dp[l+1][r-1] == r-l-1) { dp[l][r] = max(dp[l][r], dp[l+1][r-1]+2); } for(int j = l+1; j <= r-1; j++) { dp[l][r] = max(dp[l][r], dp[l][j]+dp[j+1][r]); if(c[l][j] == 1 && dp[l+1][j-1] == j-l-1) dp[l][r] = max(dp[l][r], dp[l+1][j-1]+dp[j+1][r]+2); if(c[j][r] == 1 && dp[j+1][r-1] == r-j-1) dp[l][r] = max(dp[l][r], dp[l][j-1]+dp[j+1][r-1]+2); if(c[l][j] == 1 && c[j][r] == 1 && a[r] - a[j] == a[j] - a[l] && dp[l+1][j-1] == j-l-1 && dp[j+1][r-1] == r-j-1) dp[l][r] = r-l+1; } } } cout << dp[1][n] << endl; } return 0;}
- HDU 5693:D Game(区间DP)
- HDU 5693 D Game 区间dp
- HDU 5693 D Game(区间dp)
- Hdu 5693 D Game【区间Dp】好题!
- hdu 5639 D Game 区间dp
- hdu5693(区间dp)D Game
- hdu 4597 Play Game(区间dp)
- HDU 4597 Play Game(区间dp)
- HDU 4597 - Play Game(区间DP)
- HDU-4597 Play Game (区间DP)
- hdu 4597 Play Game 区间dp
- HDU 5693 D Game
- hdu 4597 Play Game 记忆化搜索 区间dp
- HDU ACM 4597 Play Game ->区间DP+记忆化搜索
- hdu 4597 Play Game (记忆化搜索,区间dp)
- HDU 4597 Play Game(DFS,区间DP)
- HDU 4597 Play Game (博弈 + 区间dp)
- 【HDU】4742 Pinball Game 3D cdq分治+DP
- Docker的安装和测试使用
- JavaSE程序----math.random设计小游戏
- js变量数据类型特点
- 面试题总结——JAVA高级工程师
- 数值的整数次方
- HDU 5693 D Game(区间dp)
- 印刻学院_SEO入门
- [日常训练] 树上的游戏
- Python3import语句
- linux 内核调试
- 递归与栈
- 20170724_C++单例模式
- Spring boot (四) JPA-Hibernate
- 基于JavaSwing写的雷霆战机(飞机大战)