http://acm.hdu.edu.cn/showproblem.php?pid=3698

Let the light guide us

Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 62768/32768 K (Java/Others)
Total Submission(s): 759    Accepted Submission(s): 253

Problem Description

Plain of despair was once an ancient battlefield where those brave spirits had rested in peace for thousands of years. Actually no one dare step into this sacred land until the rumor that “there is a huge gold mine underneath the plain” started to spread.
Recently an accident destroyed the eternal tranquility. Some greedy fools tried using powerful bombs to find the hidden treasure. Of course they failed and such behavior enraged those spirits--the consequence is that all the human villages nearby are haunted by ghosts.
In order to stop those ghosts as soon as possible, Panda the Archmage and Facer the great architect figure out a nice plan. Since the plain can be represented as grids of N rows and M columns, the plan is that we choose ONLY ONE cell in EACH ROW to build a magic tower so that each tower can use holy light to protect the entire ROW, and finally the whole plain can be covered and all spirits can rest in peace again. It will cost different time to build up a magic tower in different cells. The target is to minimize the total time of building all N towers, one in each row.
“Ah, we might have some difficulties.” said Panda, “In order to control the towers correctly, we must guarantee that every two towers in two consecutive rows share a common magic area.”
“What?”
“Specifically, if we build a tower in cell (i,j) and another tower in cell (i+1,k), then we shall have |j-k|≤f(i,j)+f(i+1,k). Here, f(i,j) means the scale of magic flow in cell (i,j).”
“How?”
“Ur, I forgot that you cannot sense the magic power. Here is a map which shows the scale of magic flows in each cell. And remember that the constraint holds for every two consecutive rows.”
“Understood.”
“Excellent! Let’s get started!”
Would you mind helping them?

Input

There are multiple test cases.
Each test case starts with a line containing 2 integers N and M (2<=N<=100,1<=M<=5000), representing that the plain consists N rows and M columns.
The following N lines contain M integers each, forming a matrix T of N×M. The j-th element in row i (Tij) represents the time cost of building a magic tower in cell (i, j). (0<=Tij<=100000)
The following N lines contain M integers each, forming a matrix F of N×M. The j-th element in row i (Fij) represents the scale of magic flows in cell (i, j). (0<=Fij<=100000)
For each test case, there is always a solution satisfying the constraints.
The input ends with a test case of N=0 and M=0.

Output

For each test case, output a line with a single integer, which is the minimum time cost to finish all magic towers.

Sample Input

3 5

9 5 3 8 7

8 2 6 8 9

1 9 7 8 6

0 1 0 1 2

1 0 2 1 1

0 2 1 0 2

0 0

Sample Output

10

Source

2010 Asia Fuzhou Regional Contest

分析:

这题显然是Dp .....dp[i][j] = min{dp[i + 1][k] + T[i][j]} |j-k|≤f(i,j)+f(i+1,k)

可是,一看数据规模,time有点捉急额、、、

斜率优化? .....没看出来。

四边形不等式? .....还是算了吧。

看来要优化状态转移方程“有点”困难......

让我们换个思路,能不能快速取到合适的k…

|j-k|≤f(i,j)+f(i+1,k)

Dp[i][j]的最优值,一定在以j为圆心,f[i][j]为半径的区间内

而dp[i-1][j]能更新以j为圆心,f[i-1][j] 为半径的区间。

这样,我们用每个dp[i-1][j] 更新每个[j – f[i - 1][j] , j + f[i - 1][j]]范围内的值。

计算 Dp[i][j]时,只需查询[j – f[i][j] , j + f[i][j]]范围内的最小值,既RMQ

So。。。。看代码吧。。。。

AC Code:    呵呵,在HDU上排名第13.......

#include <cstdio>

using namespace std;

const int maxn = 105;

const int maxm = 5005;

const int inf = 1 << 30;

inline int L(int rt)    {return rt << 1;}

inline int R(int rt)    {return rt << 1 | 1;}

inline int min(int a,int b) {return a < b ? a : b;}

struct Node

{

    int l,r;

    int min;        // 区间最小值

    int val;

} nd[maxm << 2];

int f[maxn][maxm];

int time[maxn][maxm];

int dp[maxn][maxm];

inline void pushDown(int rt)

{

    if(nd[rt].val != inf)                            // val 有修改

    {

        nd[L(rt)].val = min(nd[L(rt)].val,nd[rt].val);

        nd[R(rt)].val = min(nd[R(rt)].val,nd[rt].val);

        nd[L(rt)].min = min(nd[L(rt)].min,nd[L(rt)].val);

        nd[R(rt)].min = min(nd[R(rt)].min,nd[R(rt)].val);

        nd[rt].val = inf;

    }

}

void build(int l,int r,int rt)                            // 建线段树

{

    nd[rt].l = l;   nd[rt].r = r;

    nd[rt].min = nd[rt].val = inf;

    if(l == r)  return;

    int mid = (l + r) >> 1;

    build(l,mid,L(rt));

    build(mid + 1,r,R(rt));

}

void update(int l,int r,int val,int rt)                     // 更新区间[l,r]

{

    if(l <= nd[rt].l && nd[rt].r <= r)

    {

        nd[rt].val = min(val,nd[rt].val);

        nd[rt].min = min(nd[rt].val,nd[rt].min);

        return;

    }

    int mid = (nd[rt].l + nd[rt].r) >> 1;

    pushDown(rt);

    if(l <= mid)    update(l,r,val,L(rt));

    if(r > mid)     update(l,r,val,R(rt));

    nd[rt].min = min(nd[L(rt)].min,nd[R(rt)].min);

}

int query(int l,int r,int rt)                            // RMQ

{

    if(l <= nd[rt].l && nd[rt].r <= r)

        return nd[rt].min;

    int ret = inf;

    int mid = (nd[rt].l + nd[rt].r) >> 1;

    pushDown(rt);

    if(l <= mid)    ret = min(ret,query(l,r,L(rt)));

    if(r > mid)     ret = min(ret,query(l,r,R(rt)));

    return ret;

}

inline void scan(int &n)                     // 读入加速

{

    char c;

    while(c = getchar(),c < '0' || c > '9');

    n = c - '0';

    while(c = getchar(),(c >= '0' && c <= '9')) n = n * 10 + c - '0';

}

int main()

{

    int n,m;

    while(scanf("%d%d",&n,&m) && (n != 0 || m != 0))

    {

        for(int i = 1;i <= n;i ++)

        for(int j = 1;j <= m;j ++)

            scan(time[i][j]);

        for(int i = 1;i <= n;i ++)

        for(int j = 1;j <= m;j ++)

            scan(f[i][j]);

        for(int i = 1;i <= m;i ++)              // 初始化边界

            dp[1][i] = time[1][i];

/////////////////////////////////////////////////////核心/////////////////////////////////////////////////////

        for(int i = 2;i <= n;i ++)

        {

            build(1,m,1);

            for(int j = 1;j <= m;j ++)

                update(j - f[i - 1][j],j + f[i - 1][j],dp[i - 1][j],1);

            for(int j = 1;j <= m;j ++)

                dp[i][j] = query(j - f[i][j],j + f[i][j],1) + time[i][j];

        }

/////////////////////////////////////////////////////END/////////////////////////////////////////////////////

        int ans = inf;

        for(int i = 1;i <= m;i ++)

            ans = min(ans,dp[n][i]);

        printf("%d\n",ans);

    }

    return 0;

}

题解 HDU 3698 Let the light guide us Dp + 线段树优化的更多相关文章

  1. hdu3698 Let the light guide us dp+线段树优化

    http://acm.hdu.edu.cn/showproblem.php?pid=3698 Let the light guide us Time Limit: 5000/2000 MS (Java ...

  2. HDU 3698 Let the light guide us

    Let the light guide us Time Limit: 2000ms Memory Limit: 32768KB This problem will be judged on HDU. ...

  3. hdu 3698 Let the light guide us(线段树优化&简单DP)

    Let the light guide us Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 62768/32768 K (Java/O ...

  4. HDU 3698 Let the light guide us(DP+线段树)(2010 Asia Fuzhou Regional Contest)

    Description Plain of despair was once an ancient battlefield where those brave spirits had rested in ...

  5. HDU 4719 Oh My Holy FFF(DP+线段树)(2013 ACM/ICPC Asia Regional Online ―― Warmup2)

    Description N soldiers from the famous "*FFF* army" is standing in a line, from left to ri ...

  6. hdu 3698 UVA1490 Let the light guide us 线段树优化DP

    题目链接 and 题目大意 hdu3698 但是 hdu的数据比较弱,所以在这luogu提交吧UVA1490 Let the light guide us 有一个\(n*m\)的平原,要求每行选一个点 ...

  7. hdu 5266 pog loves szh III(lca + 线段树)

    I - pog loves szh III Time Limit:6000MS     Memory Limit:131072KB     64bit IO Format:%I64d & %I ...

  8. hdu 3016 dp+线段树

    Man Down Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total S ...

  9. HDU 2795 Billboard(宣传栏贴公告,线段树应用)

    HDU 2795 Billboard(宣传栏贴公告,线段树应用) ACM 题目地址:HDU 2795 Billboard 题意:  要在h*w宣传栏上贴公告,每条公告的高度都是为1的,并且每条公告都要 ...

随机推荐

  1. PAT Advanced 1048 Find Coins (25) [Hash散列]

    题目 Eva loves to collect coins from all over the universe, including some other planets like Mars. On ...

  2. oracle的用户、权限、表空间的管理

    1.创建表空间 create tablespace test1_tablespace datafile 'test1file.dbf' size 10m; 2.创建临时表空间 create tempo ...

  3. python使用进程池多进程时,如何打印错误信息

    一.说明 1.python进程池进行多进程运行时,如果有错误,该进程会直接跳过,并且不会打印错误信息. 2.如果需要了解到进程内的错误信息,此时就需要通过捕获异常来输出错误信息了. 二.具体方法如下: ...

  4. sklearn KMeans聚类算法(总结)

    基本原理 Kmeans是无监督学习的代表,没有所谓的Y.主要目的是分类,分类的依据就是样本之间的距离.比如要分为K类.步骤是: 随机选取K个点. 计算每个点到K个质心的距离,分成K个簇. 计算K个簇样 ...

  5. luffy项目:基于vue与drf前后台分离项目(1)

    """ 1.业务逻辑:登录注册 - 主页(基础信息展示) - 课程页(复杂信息展示)- 课程订单生产与支付 - 上线订单生成 2.实际项目开发的技术点: git版本控制 ...

  6. Codeforces 1294E - Obtain a Permutation

    题目大意: 给定一个n*m的矩阵 可以更改任意一个位置的值 也可以选择一整列全部往上移动一位,最上方的数移动到最下方 问最少操作多少次可以把这个矩阵移动成 1 2 3 ... m m+1 m+2 m+ ...

  7. 远程SSH服务使用指南

    Author Email Yaoyao Liu yaoyaoliu@msn.com 本文所有教程以ubuntu为例,对其他unix内核系统如Debian.CentOS.macOS等也适用. 目录 安装 ...

  8. Docker搭建RabbitMQ(阿里云)

    0 环境 系统环境:centos7 服务器:阿里云 1 正文 1 获取安装RabbitMQ https://hub.docker.com/_/rabbitmq 默认rabbitmq镜像是不带web端管 ...

  9. Kafka及周边深度了解

    之前介绍了使用官方脚本自动化启动一个Fabric网络,并且所有的证书都是通过官方的命令行工具cryptogen直接生成网络中的所有节点的证书.在开发环境可以这么简单进行,但是生成环境下还是需要我们自定 ...

  10. 吴裕雄--天生自然 JAVA开发学习:封装

    public class Person { private String name; private int age; } public class Person{ private String na ...