题意:

    一根数轴上有n只怪物,第i个怪物所在的位置为ai,另有m个特殊点,第i个特殊点所在的位置为bi。你可以对怪物进行移动,若两怪物相邻,那么你不能把他们分开,移动时要看作一个整体。你可以选择向左或向右移动,直到撞到怪物,移动的次数不限制。现在要求最大数量的呆在特殊点上的怪物。 n <= 100000,m <= 2000

  分析:

    做这题的时候真的非常烦躁,卡在描述状态很久,静下心来思考才能更好地领悟。

    由于最终答案与特殊点密切相关,且特殊点是固定不变的,我们不妨以特殊点为基础作转移。接下来我们就可以分情况来考虑了:假设第i只怪兽在特殊点j的左边,那么就需要pos[j]-pos[i]只怪兽填充,即第i+1~i+pos[j]-pos[i]向左移动;反之亦然。

    然后我就思考状态,发现无论怎么想,转移都涉及到左移和右移,会出现状态重叠的情况。

    那么就要把左移和右移分开,使转移的时候不出现状态重叠的情况。我们令F[i]为前i只怪兽能到达的特殊点的最大数量,而且还带有限制,对于转移怪兽i的时候,怪兽i只能选择不动或者向左移动。那不是说怪兽可以左右移吗?是的,只是怪兽i的向右移是在怪兽i+1~n的转移中,将左右移分开了。这样F[i]所得到的方案必满足所有的怪兽小于等于第i只怪兽的位置pos[i],避免了状态的重叠,这在后面的转移当中至关重要。

    那么要如何转移呢?

      其实在上面的思考中,已经可以得到答案了。

      对于F[i]的转移,只有两种:不动或者向左移动。转移是基于特殊点的,你的转移都是为了去占满更多的特殊点,分类讨论如何占满。

      1、不动。枚举位置比怪兽i小的特殊点j,若要占据特殊点j,那么就需要i-(pos[i]-pos[j])~i-1的怪兽右移,转移方程即为:F[i] = max{F[i-(pos[i]-pos[j])-1]+1}。当然还需要注意怪兽连成一块的情况。

      2、向左移动。枚举位置特殊点j,以及预处理出位置最大不超过特殊点j的怪兽p。若要占据特殊点j,那么i-p需大于等于pos[j]-pos[p],转移方程即为:F[i] = max{F[p]+1}。这里如果出现连成一块的情况的话,就需要判断第i只怪兽是否在块的最右端,否则,又会出现状态重叠的情况。

 #include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream> using namespace std; const int maxn = ;
const int maxm = ;
int n, m, a[maxn], b[maxm];
int belong[maxn], lef_block[maxn], rig_block[maxn], Bcnt;
int p[maxm], f[maxn]; void in()
{
scanf("%d %d", &n, &m);
for (int i = ; i <= n; ++i)
scanf("%d", &a[i]);
for (int i = ; i <= m; ++i)
scanf("%d", &b[i]);
} void prepare()
{
sort(a+, a+n+);
sort(b+, b+m+);
Bcnt = ;
for (int i = ; i <= n; ++i)
{
if (a[i] != a[i-]+ || i == )
{
belong[i] = ++Bcnt;
lef_block[Bcnt] = i;
}
else
belong[i] = Bcnt;
if (a[i+] != a[i]+)
rig_block[Bcnt] = i;
}
for (int i = ; i <= m; ++i)
{
p[i] = p[i-];
while (a[p[i]+] <= b[i])
p[i] ++;
}
} void dp()
{
f[] = ;
for (int i = ; i <= n; ++i)
{
f[i] = f[i-];
for (int j = ; j <= m; ++j){
if (b[j] <= a[i])
{
//part 1 : i don't move, others rig-move
if (i-(a[i]-b[j]) >= )
{
int t = lef_block[belong[i-(a[i]-b[j])]];
f[i] = max(f[t-]+, f[i]);
}
//part 2 : i lef-move
if (b[j]-a[p[j]] <= i-p[j] && rig_block[belong[i]] == i)
{
f[i] = max(f[p[j]]+, f[i]);
}
}
else
break ;
}
}
printf("%d\n", f[n]);
} void work()
{
prepare();
dp();
} int main()
{
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
in();
work();
return ;
}

某DP题目3的更多相关文章

  1. DP题目列表/弟屁专题

    声明: 1.这份列表不是我原创的,放到这里便于自己浏览和查找题目. ※最近更新:Poj斜率优化题目 1180,2018,3709 列表一:经典题目题号:容易: 1018, 1050, 1083, 10 ...

  2. dp题目列表

    此文转载别人,希望自己能够做完这些题目! 1.POJ动态规划题目列表 容易:1018, 1050, 1083, 1088, 1125, 1143, 1157, 1163, 1178, 1179, 11 ...

  3. dp题目

    从别的地方看来,最近一直在啃DP,有个目标,更有动力了. 1.Robberies 连接 :http://acm.hdu.edu.cn/showproblem.php?pid=2955      背包; ...

  4. 插头DP题目泛做(为了对应WYD的课件)

    题目1:BZOJ 1814 URAL 1519 Formula 1 题目大意:给定一个N*M的棋盘,上面有障碍格子.求一个经过所有非障碍格子形成的回路的数量. 插头DP入门题.记录连通分量. #inc ...

  5. 很好的一个dp题目 Codeforces Round #326 (Div. 2) D dp

    http://codeforces.com/contest/588/problem/D 感觉吧,这道题让我做,我应该是不会做的... 题目大意:给出n,L,K.表示数组的长度为n,数组b的长度为L,定 ...

  6. 两道很好的dp题目【4.29考试】

    A 问题描述: 对于一个排列,考虑相邻的两个元素,如果后面一个比前面一个大,表示这个位置是上升的,用I表示,反之这个位置是下降的,用D表示.如排列3,1,2,7,4,6,5可以表示为DIIDID. 现 ...

  7. 题目1453:Greedy Tino(dp题目)

    题目链接:http://ac.jobdu.com/problem.php?pid=1453 详解链接:https://github.com/zpfbuaa/JobduInCPlusPlus 参考代码: ...

  8. 题目1452:搬寝室(dp题目)

    题目链接:http://ac.jobdu.com/problem.php?pid=1452 详解链接:https://github.com/zpfbuaa/JobduInCPlusPlus 参考代码: ...

  9. 题目1042:Coincidence(最长公共子序列 dp题目)

    题目链接:http://ac.jobdu.com/problem.php?pid=1042 详解链接:https://github.com/zpfbuaa/JobduInCPlusPlus 参考代码: ...

  10. 概率dp+期望dp 题目列表(一)

    表示对概率和期望还不是很清楚定义. 目前暂时只知道概率正推,期望逆推,然后概率*某个数值=期望. 为什么期望是逆推的,例如你求到某一个点的概率我们可以求得,然后我们只要运用dp从1~n每次都加下去就好 ...

随机推荐

  1. SVM支持向量机的基本原理

    SVM支持向量机的基本原理 对于很多分类问题,例如最简单的,一个平面上的两类不同的点,如何将它用一条直线分开?在平面上我们可能无法实现,但是如果通过某种映射,将这些点映射到其它空间(比如说球面上等), ...

  2. layui实现类似于bootstrap的模态框功能

    以前习惯了bootstrap的模态框,突然换了layui,想的用layui实现类似于bootstrap的模态框功能. 用到了layui的layer模块,例如: <!DOCTYPE html> ...

  3. 宋牧春: Linux设备树文件结构与解析深度分析(2) 【转】

    转自:https://mp.weixin.qq.com/s/WPZSElF3OQPMGqdoldm07A 作者简介 宋牧春,linux内核爱好者,喜欢阅读各种开源代码(uboot.linux.ucos ...

  4. git 还原到指定版本号

      git clone git branch -r --contains 88b92060224e96ef209565fa75c816eb9b0fae8e git checkout origin/re ...

  5. PHP--- JSON和数组的转换

    一.json_encode() <?php $arr =array ('a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5); echo json_ ...

  6. acm专题---拓扑排序+优先队列

    struct node{ int id; int cnt; node(int _id,int _cnt):id(_id),cnt(_cnt){} bool operator<(node a) c ...

  7. Linux 基础——权限管理命令chown、chgrp

    一.chown命令与chgrp命令的作用 有时你需要改变文件或目录的属主,比如有人离职或开发人员创建了一个在测试或生产环境中需要归属在系统账户下的应用.Linux提供了两个命令来实现这个功能:chow ...

  8. MySql学习笔记——存储函数

    在学习完存储过程后,今天主要回顾一下mysql中的存储函数的知识. 函数与存储过程的区别 首先,存储函数也是过程式对象之一,与存储过程相似.它们都是由SQL和过程式语句组成的代码片断,并且可以从应用程 ...

  9. Hadoop(八)Hadoop数据压缩与企业级优化

    一 Hadoop数据压缩 1.1 概述 压缩技术能够有效减少底层存储系统(HDFS)读写字节数.压缩提高了网络带宽和磁盘空间的效率.在Hadood下,尤其是数据规模很大和工作负载密集的情况下,使用数据 ...

  10. js复制文字

    一.原理分析 浏览器提供了 copy 命令 ,可以复制选中的内容 document.execCommand("copy") 如果是输入框,可以通过 select() 方法,选中输入 ...