P2254

一个朴素的想法:根据时间t来dp:
f[t][i][j]表示在第t时刻在第i行第j列所能获得的最长距离。
转移方程:f[t][i][j]=max(f[t-1][i][j],f[t][i][j]+1)(i,j为上一个合理的位置)
但O(TMN),包炸的牢底。
所以必须优化,首先把时间t换成区间k,
令f[k][i][j]表示在第k段滑行区间中在位置i,j所能获得最长距离
注意到在第k段时间内只能向某个方向最多走x步(x为区间长度),得到转移方程
f[k][i][j]=max(f[k-1][i][j],f[k][i][j]+dis(i,j,i,j))(i,j为上一个合理的位置)
这个做法的时间复杂度是O(kn^3),会超时,需要进一步优化
用单调队列优化掉内层的一个n,就可以做到O(kn^2),可以AC。

#include<bits/stdc++.h>
using namespace std;
int n,m,sx,sy,K,ans,dp[205][205];
int dx[5]={0,-1,1,0,0};
int dy[5]={0,0,0,-1,1};
struct node {
	int dp,pos;
} q[205];
char wt[205][205];
void dfs(int x,int y,int len,int d){
	int head=1,tail=0;
	for(int i=1;x >=1&&x<=n&&y >=1&&y<=m;i++,x+=dx[d],y+=dy[d]){
		if(wt[x][y]=='x')head=1,tail=0;
		else{
			while(head<=tail&&q[tail].dp+i-q[tail].pos< dp[x][y])tail--;
			q[++tail]=node{dp[x][y],i};
			if(q[tail].pos-q[head].pos>len)head++;
			dp[x][y]=q[head].dp+i-q[head].pos;
			ans=max(ans,dp[x][y]);
		}
	}
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>m>>sx>>sy>>K;
	for(int i=1;i<=n;i++)cin>>(wt[i]+1);
	memset(dp,0xf3,sizeof(dp));
	dp[sx][sy]=0;
	for(int k=1,s,t,d,len;k<=K;k++){
		cin>>s>>t>>d;
		len=t-s+1;
		if(d==1)for(int i=1;i<=m;i++)dfs(n,i,len,d);
		if(d==2)for(int i=1;i<=m;i++)dfs(1,i,len,d);
		if(d==3)for(int i=1;i<=n;i++)dfs(i,m,len,d);
		if(d==4)for(int i=1;i<=n;i++)dfs(i,1,len,d);
	}
	cout<<ans;
	return 0;
}
posted @ 2025-03-23 10:54  yzc_is_SadBee  阅读(22)  评论(0)    收藏  举报