Jumping Haybales Gym - 101617D

题意: 从左上角走到右下角,每一步走的距离是往右走1~k步或者往下走1~k步。问最少走多少步到达右下角,不可达输出-1.

 

做法:  优化下dp。1.线段树优化(卡过)。2.记录各行各列当前最小合适的位置。3.单调队列优化。

1.


#include <cstdio>
#include <algorithm>
#include <cstring>
#define inf 0x3f3f3f3f
#define mf(x) memset(x,inf,sizeof(x))
using namespace std;

#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define root 1,n,1
const int MAXN = 2134;
const int INF = 0x3f3f3f3f;
int row[MAXN][MAXN<<2], col[MAXN][MAXN<<2];
char s[MAXN][MAXN];
int dp[MAXN][MAXN];
void PushUp(int *MIN, int rt) {
	MIN[rt] = min(MIN[rt<<1], MIN[rt<<1|1]);
}

void Build(int *MIN, int l, int r, int rt) {
	if(l == r) {
        MIN[rt] = INF;
		return;
	}
	int m = (l + r) >> 1;
	Build(MIN, lson);
	Build(MIN, rson);
	PushUp(MIN, rt);
}

void UpdateV(int *MIN, int p,int v, int l, int r, int rt) {
	if(l == r) {
		MIN[rt] = min(MIN[rt], v);
		return;
	}
	int m = (l + r) >> 1;
	if(p <= m) UpdateV(MIN, p, v,lson);
	else UpdateV(MIN, p, v, rson);
	PushUp(MIN, rt);
}

int QueryMin(int *MIN, int L, int R, int l, int r, int rt) {
	if(L<=l && r<=R) return MIN[rt];
	int m = (l + r) >> 1;
	int ret = INF;
	if(L <= m) ret = min(ret, QueryMin(MIN, L, R, lson));
	if(R > m) ret = min(ret, QueryMin(MIN, L, R, rson));
	return ret;
}
int main(){
    int n, k;
    scanf("%d%d", &n,&k);
    for(int i=1;i<=n;i++){
        scanf("%s", s[i]+1);
    }
    for(int i=1;i<=n;i++){
        Build(row[i], 1, n, 1);
        Build(col[i], 1, n, 1);
    }
    UpdateV(row[1], 1, 0, root);
    UpdateV(col[1], 1, 0, root);
    mf(dp);
    dp[1][1] = 0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(i==1 && j==1) continue;
            if(s[i][j] == '.'){
                int tp = QueryMin(row[i],max(1,j-k),j,root);
                tp = min(tp, QueryMin(col[j],max(1,i-k),i,root));
                if(tp != INF){
                    dp[i][j] = min(dp[i][j], tp+1);
                    //printf("i:%d j:%d  dp:%d\n",i,j,dp[i][j]);
                    UpdateV(row[i], j, dp[i][j], root);
                    UpdateV(col[j], i, dp[i][j], root);
                }
            }

        }
    }
    if(dp[n][n] == INF) puts("-1");
    else printf("%d\n", dp[n][n]);
    return 0;
}

2.

// 单点增减/替换,区间查询

#include <cstdio>
#include <algorithm>
#include <cstring>
#define inf 0x3f3f3f3f
#define mf(x) memset(x,inf,sizeof(x))
#define ms(x) memset(x, 0, sizeof(x))
using namespace std;

#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define root 1,n,1
const int MAXN = 2134;
int row[MAXN], col[MAXN];
char s[MAXN][MAXN];
int dp[MAXN][MAXN];
int main(){
    int n, k;
    scanf("%d%d", &n,&k);
    for(int i=1;i<=n;i++){
        scanf("%s", s[i]+1);
    }
    mf(dp);
    ms(row), ms(col);

    dp[1][1] = 0;

    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(s[i][j]!='.') continue;
            for(;col[j]<i;col[j]++){
                if((i - col[j])<=k  && s[col[j]][j] == '.') break;
            }
            dp[i][j] = min(dp[i][j], dp[col[j]][j]+1);
            for(;row[i]<j;row[i]++){
                if((j - row[i])<=k && s[i][row[i]]  == '.') break;
            }
            dp[i][j] = min(dp[i][j], dp[i][row[i]]+1);
            if(dp[i][j] <= dp[i][row[i]]) row[i] = j;
            if(dp[i][j] <= dp[col[j]][j]) col[j] = i;
        }
    }
    if(dp[n][n] == inf) puts("-1");
    else printf("%d\n", dp[n][n]);
    return 0;
}

3.

没用这个试

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值