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;
}

浙公网安备 33010602011771号