hdu 3698 UVA1490 Let the light guide us 线段树优化DP
题目链接 and 题目大意
hdu3698
但是 hdu的数据比较弱,所以在这luogu提交吧UVA1490 Let the light guide us
有一个\(n*m\)的平原,要求每行选一个点,选\(n\)个点建造塔楼。
平原上每个点都有他自己的花费时间和魔法值。
为了正确控制塔楼,我们必须保证连续两排的每两座塔共用一个共同的魔法区域。
也就是要求每两行相邻的点都满足如下关系:
如果第\(i\)行选\(j\),第\(i+1\)行选\(k\),则需\(|j-k|≤f(i,j)+f(i+1,k)\)。
问花费的总时间最少为多少?
输入\(n,m\)。
再输入两个\(n*m\)的矩阵。
第一个矩阵 $T[i][j] $表示的是花费时间,
第二个矩阵 \(f[i][j]\) 表示的是魔法值\ \
思路\
如果\(m<=100\),那么这题就是个\(O(n*m{2})\)的沙比提\ \
for (int k = 2; k <= n; ++k) {
for (int i = 1; i <= m; ++i) {
for (int j = 1 ; j <= m; ++ j) {
if (abs(i - j) <= f[k][i] + f[k - 1][j] ) {
dp[k][i] = min(dp[k][i], dp[k - 1][j]);
}
}
dp[k][i] += t[k][i];
}
}
但她并是不,\(m<=1000\)
考虑如何优化一下
$abs(i - j) <= f[k][i] + f[k - 1][j] \(
\)abs(i-j)\(就是\)i\(和\)j\(之间的距离
就是\)f[k][i] +f[k-1][j]$ 要大于i和j之间的距离(这里可以当成数轴上面)
我们先看\(k\)这一行
他能给下一行(也就是k+1)提供价值的区间至少为\([i-f[k][i],i+f[k][i])\),或者更大
我们再看\(k+1\)这一行
他能取到的区间(也就是k)的区间至少为\([j-f[k+1][j],j+f[k+1][j])\),或者更大
如果他们的区间有交集,则说明他们可以由\(k\)向\(k+1\)转移
这个就可以用一颗区间加数,区间求min的线段树维护一下
复杂度\(O(n*mlogm)\)
hdu数据很水,要去luogu测!!!
当然,dp方程你可以压维,但压不压的没有啥意义反正你都开了两个一样大的数组了,多开一个又杂
两份代码
暴力代码\(n*m*m\)
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn = 107;
const int maxm = 5007;
const int inf = 0x3f3f3f3f;
int n, m, t[maxn][maxm], f[maxn][maxm], dp[maxn][maxm];
int read() {
int x = 0, f = 1; char s = getchar();
for (; s < '0' || s > '9'; s = getchar()) if (s == '-') f = -1;
for (; s >= '0' && s <= '9'; s = getchar()) x = x * 10 + s - '0';
return x * f;
}
int abs(int a) {
return a > 0 ? a : -a;
}
int main() {
while (233) {
// read
n = read(), m = read();
if (n == 0 && m == 0) break;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
t[i][j] = read();
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
f[i][j] = read();
//init
memset(dp, inf, sizeof(dp));
for (int i = 1; i <= m; ++i)
dp[1][i] = t[1][i];
//dp
for (int k = 2; k <= n; ++k) {
for (int i = 1; i <= m; ++i) {
for (int j = 1 ; j <= m; ++ j) {
if (abs(i - j) <= f[k][i] + f[k - 1][j] ) {
dp[k][i] = min(dp[k][i], dp[k - 1][j]);
}
}
dp[k][i] += t[k][i];
}
}
//printf
int ans = inf;
for (int i = 1; i <= n; ++i)
ans = min(ans, dp[n][i]);
printf("%d\n", ans);
}
return 0;
}
线段树优化\(n*m*logm\) \\
#include <bits/stdc++.h>
#define ls rt<<1
#define rs rt<<1|1
using namespace std;
const int maxn=107;
const int maxm=5007;
const int inf=0x7fffffff;
int n,m,a[maxn][maxm],b[maxn][maxm],f[maxn][maxm];
struct node {
int l,r;
int mi,lazy;
}e[maxm<<4];
int read() {
int x = 0, f = 1; char s = getchar();
for (; s < '0' || s > '9'; s = getchar()) if (s == '-') f = -1;
for (; s >= '0' && s <= '9'; s = getchar()) x = x * 10 + s - '0';
return x * f;
}
void build(int l,int r,int rt) {
e[rt].l=l,e[rt].r=r,e[rt].mi=inf,e[rt].lazy=inf;
if(l==r) return;
int mid=(l+r)>>1;
build(l,mid,ls);
build(mid+1,r,rs);
}
void pushup(int rt) {
e[rt].mi=min(e[ls].mi,e[rs].mi);
}
void pushdown(int rt) {
if(e[rt].lazy!=inf) {
e[ls].lazy=min(e[ls].lazy,e[rt].lazy);
e[rs].lazy=min(e[rs].lazy,e[rt].lazy);
e[ls].mi=min(e[ls].mi,e[ls].lazy);
e[rs].mi=min(e[rs].mi,e[rs].lazy);
e[rt].lazy=inf;
}
}
void update(int L,int R,int k,int rt) {
if(L<=e[rt].l&&e[rt].r<=R) {
e[rt].lazy=min(e[rt].lazy,k);
e[rt].mi=min(e[rt].mi,e[rt].lazy);
return;
}
pushdown(rt);
int mid=(e[rt].l+e[rt].r)>>1;
if(L<=mid) update(L,R,k,ls);
if(R>mid) update(L,R,k,rs);
pushup(rt);
}
int query(int L,int R,int rt) {
if(L<=e[rt].l&&e[rt].r<=R) {
return e[rt].mi;
}
pushdown(rt);
int mid=(e[rt].l+e[rt].r)>>1,ans=inf;
if(L<=mid) ans=min(ans,query(L,R,ls));
if(R>mid) ans=min(ans,query(L,R,rs));
pushup(rt);
return ans;
}
void debug1() {
printf("debug\n");
printf(" %d\n", e[1].mi);
printf(" %d %d\n", e[2].mi, e[3].mi );
printf(" %d %d %d %d\n", e[4].mi, e[5].mi, e[6].mi, e[7].mi );
printf(" %d %d %d %d %d %d %d %d\n", e[8].mi,
e[9].mi, e[10].mi, e[11].mi, e[12].mi, e[13].mi, e[14].mi, e[15].mi);
}
void debug()
{
for(int i=1;i<=n;++i,puts(""))
for(int j=1;j<=m;++j)
cout<<f[i][j]<<" ";
}
int main()
{
while(1)
{
n=read(),m=read();
if(n==0 && m==0) return 0;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
a[i][j]=read();
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
b[i][j]=read();
for(int i=1;i<=m;++i)
f[1][i]=a[1][i];
for(int i=2;i<=n;++i) {
build(1,m,1);
for(int j=1;j<=m;++j) {
int l=max(1,j-b[i-1][j]),r=min(m,j+b[i-1][j]);
update(l,r,f[i-1][j],1);
}
for(int j=1;j<=m;++j) {
int l=max(1,j-b[i][j]),r=min(m,j+b[i][j]);
f[i][j]=query(l,r,1)+a[i][j];
}
}
int ans=inf;
for(int i=1;i<=m;++i)
ans=min(ans,f[n][i]);
printf("%d\n", ans);
}
return 0;
}
hdu 3698 UVA1490 Let the light guide us 线段树优化DP的更多相关文章
- 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 ...
- HDU多校第三场 Hdu6606 Distribution of books 线段树优化DP
Hdu6606 Distribution of books 题意 把一段连续的数字分成k段,不能有空段且段和段之间不能有间隔,但是可以舍去一部分后缀数字,求\(min(max((\sum ai ))\ ...
- hdu 5266 pog loves szh III(lca + 线段树)
I - pog loves szh III Time Limit:6000MS Memory Limit:131072KB 64bit IO Format:%I64d & %I ...
- HDU 2795 Billboard(宣传栏贴公告,线段树应用)
HDU 2795 Billboard(宣传栏贴公告,线段树应用) ACM 题目地址:HDU 2795 Billboard 题意: 要在h*w宣传栏上贴公告,每条公告的高度都是为1的,并且每条公告都要 ...
- 题解 HDU 3698 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 ...
- 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 ...
- hdu 4521 小明系列问题——小明序列(线段树 or DP)
题目链接:hdu 4521 本是 dp 的变形,却能用线段树,感觉好强大. 由于 n 有 10^5,用普通的 dp,算法时间复杂度为 O(n2),肯定会超时.所以用线段树进行优化.线段树维护的是区间内 ...
- HDU 4521 小明系列问题——小明序列 (线段树维护DP)
题目地址:HDU 4521 基本思路是DP.找前面数的最大值时能够用线段树来维护节省时间. 因为间隔要大于d. 所以能够用一个队列来延迟更新,来保证每次询问到的都是d个之前的. 代码例如以下: #in ...
- hdu 5091 给定矩形覆盖尽量多点 扫描线+线段树
http://acm.hdu.edu.cn/showproblem.php?pid=5091 给你10000以内的敌舰的坐标(即分别为x,y),要求用W*H的矩形去围住一个区域,使得这个区域内的敌舰最 ...
随机推荐
- 【linux echo -e命令】
man帮助的解释是,允许后面的输出进行转义,假设你是 echo -e "i will use \n $HOME" 输出的将是i will use/root(当前用户的主目录)如果是 ...
- A Simple Problem with Integers---poj3468线段树
http://poj.org/problem?id=3468 题意:有一个比较长的区间可能是100000.长度, 每个点都有一个值(值还比较大), 现在有一些操作: C a b c, 把区间a-- ...
- 食物链--poj1182(并查集含有关系)
http://poj.org/problem?id=1182 题意应该就不用说了 再次回到食物链这道题,自己写了一遍,一直wa...原因竟然是不能用多实例,我也是醉了,但是我真的彻底的理解了,那 ...
- Python开发【算法】:斐波那契数列两种时间复杂度
斐波那契数列 概述: 斐波那契数列,又称黄金分割数列,指的是这样一个数列:0.1.1.2.3.5.8.13.21.34.……在数学上,斐波纳契数列以如下被以递归的方法定义:F(0)=0,F(1)=1, ...
- linux,centOS,用LNMP搭建wordpress,更新固定连接--全流程
下午到晚上的时间,买了个linux服务器,用的centOS系统,遇到各种问题! 1.用putty,ssh到vps后,根据网上命令,一步步下载并安装,具体步骤可以看一下网上教程,LNMP.org站上的教 ...
- redis 在windows 上面的安装和使用,集群搭建
redis作为nosql数据库,将数据存储到内存中(缓存),具有非常高的性能.下面讲解一下redis的安装及java api的使用. 1:redis 安装 windows 上面直接下载msi文件,安装 ...
- [git]git版本管理学习记录
今天看到别人用这玩意记录自己的进度, 我也学习了一下. 1,适当的工具会提升效率 2,关注点还是得放在代码本身上. github/gitignore github提供了各种gitignore文件 有p ...
- [LintCode] 395. Coins in a Line 2_Medium tag: Dynamic Programming, 博弈
Description There are n coins with different value in a line. Two players take turns to take one or ...
- 软件包管理:rpm命令管理-安装升级与卸载
严格区分大小写 卸载命令不许再包的目录下执行.
- 【环境变量】删掉centos原有的openjdk并安装sun jdk
一.卸载原有openjdk rpm -qa | grep java 之后,将展示出来的全部卸载掉,我这里是5个 rpm -e --nodeps java-1.7.0-openjdk-1.7.0.111 ...