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;
}

posted @ 2018-10-12 09:12  ComplexPug  阅读(187)  评论(0编辑  收藏  举报