题意: 从左上角走到右下角,每一步走的距离是往右走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.
没用这个试