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. Android 消息推送流程机制

    1.引言 所谓的消息推送就是从服务器端向移动终端发送连接,传输一定的信息.比如一些新闻客户端,每隔一段时间收到一条或者多条通知,这就是从服务器端传来的推送消息:还比如常用的一些IM软件如微信.GTal ...

  2. python编程:从入门到实践----第五章>if 语句

    一.一个简单示例 假设有一个汽车列表,并想将其每辆汽车的名称打印出来.遇到汽车名‘bmw’,以全大写打印:其他汽车名,首字母大写 cars=['audi','bmw','subaru','toyota ...

  3. 零相关|回归|相关|相关系数|回归解释相关|r判断相关性|相关系数的区间估计|数据类型|非线性回归

    零相关是什么? 零相关亦称“不相关”.相关的一种.两个变量的相关系数r=0时的相关.零相关表示两个变量非线性相关,这时两个变量可能相互独立,也可能曲线相关.对于正态变量,两个变量零相关与两个变量相互独 ...

  4. Deep-Learning-with-Python] 文本序列中的深度学习

    https://blog.csdn.net/LSG_Down/article/details/81327072 将文本数据处理成有用的数据表示 循环神经网络 使用1D卷积处理序列数据 深度学习模型可以 ...

  5. 从西班牙、英国出租车与Uber之争,看共享打车未来发展趋势

    一种新事物.新服务的崛起,必然会损害传统事物和服务的既得利益.比如在电灯泡发明之初,煤油灯企业就将电灯泡专利收购并"雪藏"以维护自己的利益.而电商的崛起,也让传统的线下实体店受到严 ...

  6. 好看的UI组合,为以后自己写组件库做准备

    1. 黑色格子背景 { color: rgb(255, 255, 255); text-shadow: 1px 1px 0 rgba(0,0,0,.3); rgb(62, 64, 74); backg ...

  7. LFW Face Database下载

    http://vis-www.cs.umass.edu/lfw/ Download the database: All images as gzipped tar file (173MB, md5su ...

  8. 吴裕雄--天生自然 pythonTensorFlow自然语言处理:交叉熵损失函数

    import tensorflow as tf # 1. sparse_softmax_cross_entropy_with_logits样例. # 假设词汇表的大小为3, 语料包含两个单词" ...

  9. Java实现生产与消费(完美注释版)

    /** * 2019年8月8日17:42:23 * 目的:Java多线程实现生产与消费 * @author 张涛 * * 多态: * 一个父类的引用既可以指向父类对象 * 也可以指向子类对象 * 它会 ...

  10. 一张图看懂三维GIS