P2254 [NOI2005]瑰丽华尔兹
\(f(i,x,y)\)表示\(i\)时刻在\((x,y)\)点的最长路径
1900可以固定,也可以随波逐流
\[f(i,x,y) = \max(f(i-1,x,y),f(i-1,x',y')+1)
\]
时间复杂度\(O(n^2t)\)
爆炸了,只能过一半
再看数据范围,显然\(O(n^2k)\)才是正解
考虑同一时间段,停和不停可以化为一段连续的区间(就算你时停时不停,也可以把停放到一起,不停放到一起,并不影响)
也就是说如果按时间段来考虑,可以看做一直在走(这么明显的东西扯这么半天)
设\(f(i,x,y)\)表示当前在第\(i\)个区间,在\((x,y)\)的最长路径
有
\[f(i,x,y) = \max(f(i-1,x',y')+dis(x',y',x,y))
\]
时间复杂度\(O(n^3k)\)
但区间长度是有范围的,变化的那一维就有了范围,辣么可以单调队列优化变化的那一维
时间复杂度\(O(n^2k)\),稳过
代码
const int N = 210;
int n,m,sx,sy,k,ans,f[N][N];
int dx[] = {0,-1,1,0,0},dy[] = {0,0,0,-1,1};
char a[N][N];
struct node {
int id,f;
node(int id = 0,int f = 0):id(id),f(f){}
}q[N];int l,r;
void calc(int x,int y,int L,int d) {
l = 1,r = 0;
for(int i = 1;x >= 1 && y >= 1 && x <= n && y <= m; ++i,x += dx[d],y += dy[d]) {
if(a[x][y] == 'x') l = 1,r = 0;
else {
while(l <= r && q[r].f+i-q[r].id < f[x][y]) --r;
q[++r] = node(i,f[x][y]);//入的是k-1
while(l <= r && q[l].id < i-L) ++l;
if(l <= r) f[x][y] = q[l].f+(i-q[l].id),ans = max(ans,f[x][y]);//求的是k
else f[x][y] = -0x3f3f3f3f;
}
}
}
int main() {
in(n); in(m); in(sx); in(sy); in(k);
memset(f,~0x3f,sizeof(f));
f[sx][sy] = 0;
for(int i = 1;i <= n; ++i) scanf("%s",a[i]+1);
for(int i = 1,s,t,d;i <= k; ++i) {
in(s); in(t); in(d);
int L = t-s+1;
if(d == 1) for(int i = 1;i <= m; ++i) calc(n,i,L,d);
if(d == 2) for(int i = 1;i <= m; ++i) calc(1,i,L,d);
if(d == 3) for(int i = 1;i <= n; ++i) calc(i,m,L,d);
if(d == 4) for(int i = 1;i <= n; ++i) calc(i,1,L,d);
}
out(ans);
return 0;
}