BZOJ1499: [NOI2005]瑰丽华尔兹

【传送门:BZOJ1499


简要题意:

  有一个字符矩阵,'.'表示能走,'x'表示不能走,给出起点的坐标,起点有一座钢琴,每单位时间可以移动一格,共有k个时间段,然后再给出每个时间段起始时间和结束时间,以及当前时间段能够移动的方向。而在某个时间,可以控制钢琴不动,钢琴不能走到'x'而且不能走出矩阵

  求出钢琴最多能走多少格


题解:

  一眼DP题

  设f[t][i][j]表示第t时间走到(i,j)最多能走的格数,f[t][i][j]=max(f[t-1][i][j],f[t-1][i-dx[i]][j-dy[i]]+1),时间复杂度O(nmT),超时

  我们重新搞DP方程,设f[k][i][j]表示第k时间段走到(i,j)最多能走的格数,f[k][i][j]=max(f[k][i][j],f[k-1][i-dx[i]*c][j-dy[i]*c]+c),c为第k-1时间段走多长时间

  因为每个时间段都是对于一行或者一列进行操作的,所以我们可以分成四种情况来单调队列

  这样子时间复杂度就是O(nmk)

  还要提的一点是,最好用滚动数组,优化一下空间


参考代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
char st[210][210];
struct node
{
    int d,t;
}T[210];
int f[2][210][210];
int list[210];
int main()
{
    int n,m,x,y,k;
    scanf("%d%d%d%d%d",&n,&m,&x,&y,&k);
    for(int i=1;i<=n;i++) scanf("%s",st[i]+1);
    for(int i=1;i<=k;i++)
    {
        int l,r;
        scanf("%d%d%d",&l,&r,&T[i].t);
        T[i].d=r-l+1;
    }
    memset(f,-63,sizeof(f));
    f[0][x][y]=0;
    int now=0,last=1,head,tail;
    for(int K=1;K<=k;K++)
    {
        now^=1;last^=1;
        if(T[K].t==1)
        {
            for(int j=1;j<=m;j++)
            {
                head=1;tail=0;
                for(int i=n;i>=1;i--)
                {
                    if(st[i][j]=='x') head=1,tail=0;
                    while(head<=tail&&list[head]-i>T[K].d) head++;
                    if(head<=tail) f[now][i][j]=f[last][list[head]][j]+list[head]-i;
                    while(head<=tail&&f[last][i][j]>f[last][list[tail]][j]+list[tail]-i) tail--;
                    list[++tail]=i;
                    f[now][i][j]=max(f[now][i][j],f[last][i][j]);
                }
            }
        }
        if(T[K].t==2)
        {
            for(int j=1;j<=m;j++)
            {
                head=1;tail=0;
                for(int i=1;i<=n;i++)
                {
                    if(st[i][j]=='x') head=1,tail=0;
                    while(head<=tail&&i-list[head]>T[K].d) head++;
                    if(head<=tail) f[now][i][j]=f[last][list[head]][j]+i-list[head];
                    while(head<=tail&&f[last][i][j]>f[last][list[tail]][j]+i-list[tail]) tail--;
                    list[++tail]=i;
                    f[now][i][j]=max(f[now][i][j],f[last][i][j]);
                }
            }
        }
        if(T[K].t==3)
        {
            for(int i=1;i<=n;i++)
            {
                head=1;tail=0;
                for(int j=m;j>=1;j--)
                {
                    if(st[i][j]=='x') head=1,tail=0;
                    while(head<=tail&&list[head]-j>T[K].d) head++;
                    if(head<=tail) f[now][i][j]=f[last][i][list[head]]+list[head]-j;
                    while(head<=tail&&f[last][i][j]>f[last][i][list[tail]]+list[tail]-j) tail--;
                    list[++tail]=j;
                    f[now][i][j]=max(f[now][i][j],f[last][i][j]);
                }
            }
        }
        if(T[K].t==4)
        {
            for(int i=1;i<=n;i++)
            {
                head=1;tail=0;
                for(int j=1;j<=m;j++)
                {
                    if(st[i][j]=='x') head=1,tail=0;
                    while(head<=tail&&j-list[head]>T[K].d) head++;
                    if(head<=tail) f[now][i][j]=f[last][i][list[head]]+j-list[head];
                    while(head<=tail&&f[last][i][j]>f[last][i][list[tail]]+j-list[tail]) tail--;
                    list[++tail]=j;
                    f[now][i][j]=max(f[now][i][j],f[last][i][j]);
                }
            }
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) ans=max(f[now][i][j],ans);
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2018-03-08 18:56  Star_Feel  阅读(297)  评论(1编辑  收藏  举报