题目大意
现在有一个 的矩阵,给定的起始点上有个钢琴,矩阵上有些方格是障碍物,用连续的区间 和一个参数 表示在时间 时会向 方向滑动(上下左右),当然每个时间点可以选择让钢琴不动,不允许钢琴超出边界或者碰到障碍,询问钢琴可能走的最远距离是多少。
其中 ,区间个数 ,区间最大的右端点
题解
首先对于这个题目我们有一个很朴素的暴力,也就是记 表示在时间点 时自己在 能走到的最远距离,转移只需要考虑这个时间点是否让钢琴不动:
$x',y'O(Tn^2)kf_{i,x,y}i(x,y)dis(x,y)(x',y')(x',y')nO(n^3k)g = f_{i-1}xyxf_x \to f_{x+1}O(n^2k)$,可以通过该题。
代码
#include <algorithm> #include <iostream> #include <cstring> #include <climits> #include <cstdlib> #include <cstdio> #include <bitset> #include <vector> #include <cmath> #include <ctime> #include <queue> #include <stack> #include <map> #include <set> #define fi first #define se second #define U unsigned #define P std::pair<int,int> #define Re register #define LL long long #define pb push_back #define MP std::make_pair #define all(x) x.begin(),x.end() #define CLR(i,a) memset(i,a,sizeof(i)) #define FOR(i,a,b) for(Re int i = a;i <= b;++i) #define ROF(i,a,b) for(Re int i = a;i >= b;--i) #define DEBUG(x) std::cerr << #x << '=' << x << std::endl const int MAXN = 200+5; const int dx[4] = {-1,1,0,0}; const int dy[4] = {0,0,-1,1}; int n,m,sx,sy,k,now,ans; char str[MAXN][MAXN]; int f[2][MAXN][MAXN]; P q[MAXN];// pair<val,pos> inline void calc(int x,int y,int len,int d){ d--;int head = 1,tail = 0; for(int i = 1;x >= 1 && x <= n && y >= 1 && y <= m;x += dx[d],y += dy[d],++i){ if(str[x][y] == 'x') {head = 1,tail = 0;continue;} while(head <= tail && q[tail].fi + i - q[tail].se < f[now^1][x][y]) tail--; q[++tail] = MP(f[now^1][x][y],i); if(q[tail].se - q[head].se > len) head++; f[now][x][y] = q[head].fi + i - q[head].se; ans = std::max(ans,f[now][x][y]); } } int main(){ scanf("%d%d%d%d%d",&n,&m,&sx,&sy,&k); FOR(i,1,n) scanf("%s",str[i]+1);CLR(f,0xf3); f[now][sx][sy] = 0; while(k--){ now ^= 1;int l,r,d;scanf("%d%d%d",&l,&r,&d); if(d == 1) FOR(i,1,m) calc(n,i,r-l+1,d); if(d == 2) FOR(i,1,m) calc(1,i,r-l+1,d); if(d == 3) FOR(i,1,n) calc(i,m,r-l+1,d); if(d == 4) FOR(i,1,n) calc(i,1,r-l+1,d); } printf("%d\n",ans); return 0; }