noi2005<瑰丽华尔兹>
链接:https://www.luogu.org/problemnew/show/P2254
题解:
思路很好想,若用f[i][j][k]表示k时间到达i,j位置的最大花费 转移即从当前方向转移
时间复杂度(n*m*t) 空间复杂度(n*m*t)
注意到题目给出了大T,只有200,n*m*T的时间是可以接受的
容易发现f[i][j][k]可以由一段t时刻转移而来,而这个可以由单调队列做到o(1)修改
另外由于可以不动,所以当t2>t1时,t2状态一定优于t1,时间这一维在数组中可以省略
注意:分4种情况讨论的单调队列不是很好调试,要背清楚模板
单调队列模板:
#include <btis/stdc++.h>
using namespace std;
int h,t;
void insert(int x,int y)
{
for (int i=t;i>=h;i--)
if (条件) break;
q[++i]=y; id[++i]=x;
}
int main()
{
h=1,t=0;{队列的头要在开始处}
for (int i=1;i<=n;i++)
{
if (h<=t&&id[h]+x<i) h++;{要保证元素不为空}
//更新
insert(i,值);
}
}
这道题中的单调队列还需要做一些处理
方程f[i][j]=max{f[i-k][j]+k}; 我们可以在加入单调队列时对每个元素-j,那么比较时就是等价的,最后再加上j就可以了
这是一种基本的dp优化
代码:
#include <bits/stdc++.h>
using namespace std;
int n,m,x,y,k;
char c;
const int maxn=500;
bool f[maxn][maxn];
int q[maxn],len[maxn],id[maxn],p[maxn],h,t,dp[maxn][maxn],hh[maxn],tt[maxn],fx[maxn];
void insert(int x,int y)
{
int i;
for (i=t;i>=h;i--)
{
if (y<p[i]) break;
}
p[++i]=y; t=i;
id[i]=x;
}
int main()
{
freopen("noip.in","r",stdin);
freopen("noip.out","w",stdout);
cin>>n>>m>>x>>y>>k;
memset(f,true,sizeof(f));
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
cin>>c;
if (c=='x') f[i][j]=false;
}
for (int i=1;i<=k;i++)
{
cin>>hh[i]>>tt[i]>>fx[i];
len[i]=tt[i]-hh[i]+1;
}
memset(dp,-1,sizeof(dp));
dp[x][y]=0;
for (int i=1;i<=k;i++)
{
if (fx[i]==3)
{
for (int j1=1;j1<=n;j1++)
{
h=1;t=0;
for (int j2=m;j2>=1;j2--)
{
if (id[h]-len[i]>j2&&h<=t) h++;
if (f[j1][j2]!=0)
{
int tmp=dp[j1][j2];
if (h<=t)
{
int x=h;
dp[j1][j2]=max(dp[j1][j2],p[x]+m-j2);
}
if (tmp!=-1) insert(j2,tmp-(m-j2));
} else
{
h=1;t=0;
}
}
}
}
if (fx[i]==4)
{
for (int j1=1;j1<=n;j1++)
{
h=1;t=0;
for (int j2=1;j2<=m;j2++)
{
if (id[h]+len[i]<j2&&h<=t) h++;
if (f[j1][j2]!=0)
{
int tmp=dp[j1][j2];
if (h<=t)
{
int x=h;
dp[j1][j2]=max(dp[j1][j2],p[x]+j2);
}
if (tmp!=-1) insert(j2,tmp-j2);
} else
{
h=1;t=0;
}
}
}
}
if (fx[i]==1)
{
for (int j1=1;j1<=m;j1++)
{
h=1;t=0;
for (int j2=n;j2>=1;j2--)
{
if (id[h]-len[i]>j2&&h<=t) h++;
if (f[j2][j1]!=0)
{
int tmp=dp[j2][j1];
if (h<=t)
{
int x=h;
dp[j2][j1]=max(dp[j2][j1],p[x]+n-j2);
}
if (tmp!=-1) insert(j2,tmp-(n-j2));
} else
{
h=1;t=0;
}
}
}
}
if (fx[i]==2)
{
for (int j1=1;j1<=m;j1++)
{
h=1;t=0;
for (int j2=1;j2<=n;j2++)
{
if (id[h]+len[i]<j2&&h<=t) h++;
if (f[j2][j1]!=0)
{
int tmp=dp[j2][j1];
if (h<=t)
{
int x=h;
dp[j2][j1]=max(dp[j2][j1],p[x]+j2);
}
if (tmp!=-1) insert(j2,tmp-j2);
} else
{
h=1;t=0;
}
}
}
}
}
int ans=-1;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++)
{
ans=max(ans,dp[i][j]);
}
}
cout<<ans;
}