首页 > 其他 > 详细

NOI2005 瑰丽华尔兹

时间:2019-06-15 21:39:02      阅读:107      评论:0      收藏:0      [点我收藏+]

题目链接:戳我

先化简一下题意:一共n次操作,每次按照给定方向可以走[0,r-l+1]个格子,障碍物格子不能走,问到最后最大的路径长度为多少?

60pts做法:
\(dp[i][j][k]\)表示在执行完第k段的操作之后,的最大答案。
\(dp[i][j][k]=max(dp[i][j][k],dp[x][y][k-1]+calc(i,j,x,y))\)
其中x,y为可以通过第k次操作到达i,j的格子。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define MAXN 210
using namespace std;
int n,m,st_x,st_y,K;
int dp[MAXN][MAXN][MAXN];
char s[MAXN][MAXN];
struct Node{int op,l,r,len;}node[MAXN];
inline int calc(int a,int b)
{
    if(a<b) swap(a,b);
    return a-b;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
//  freopen("ce.out","w",stdout);
    #endif
    scanf("%d%d%d%d%d",&n,&m,&st_x,&st_y,&K);
    for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
    for(int i=1;i<=K;i++) 
    {
        scanf("%d%d%d",&node[i].l,&node[i].r,&node[i].op);
        node[i].len=node[i].r-node[i].l+1;
    }
    memset(dp,-0x3f,sizeof(dp));
    dp[st_x][st_y][0]=0;
    for(int k=1;k<=K;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                if(node[k].op==4) 
                {
                    int x=i;
                    for(int y=j;y>=max(1,j-node[k].len);y--)
                    {
                        if(s[x][y]=='x') break;
                        dp[i][j][k]=max(dp[i][j][k],dp[x][y][k-1]+calc(j,y));
                    }
                }
                else if(node[k].op==3)
                {
                    int x=i;
                    for(int y=j;y<=min(m,j+node[k].len);y++)
                    {
                        if(s[x][y]=='x') break;
                        dp[i][j][k]=max(dp[i][j][k],dp[x][y][k-1]+calc(j,y));
                    }
                }
                else if(node[k].op==1)
                {
                    int y=j;
                    for(int x=i;x<=min(n,i+node[k].len);x++)
                    {
                        if(s[x][y]=='x') break;
                        dp[i][j][k]=max(dp[i][j][k],dp[x][y][k-1]+calc(i,x));
                    }
                }
                else if(node[k].op==2)
                {
                    int y=j;
                    for(int x=i;x>=max(1,i-node[k].len);x--)
                    {
                        if(s[x][y]=='x') break;
                        dp[i][j][k]=max(dp[i][j][k],dp[x][y][k-1]+calc(i,x));
                    }
                }
            }
    int ans=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            ans=max(ans,dp[i][j][K]);
    printf("%d\n",ans);
    return 0;
}

100pts做法

就是我们发现最内层转移是可以利用单调队列优化,把\(O(n^2)\)转化成\(O(n)\)

然后就星了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 210
#define INF 0x3f3f3f3f
using namespace std;
int n,m,X,Y,K,ans;
int f[2][MAXN][MAXN],q[MAXN];
char s[MAXN][MAXN];
struct Node{int l,r,op,len;}node[40010];
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d%d%d%d%d",&n,&m,&X,&Y,&K);
    for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
    for(int i=1;i<=K;i++) scanf("%d%d%d",&node[i].l,&node[i].r,&node[i].op);
    for(int i=1;i<=K;i++) node[i].len=node[i].r-node[i].l+1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            f[0][i][j]=-INF;
    f[0][X][Y]=0;
    int now=1,pre=0;
    for(int k=1;k<=K;k++,now^=1,pre^=1)
    {
        if(node[k].op==1)
        {
            for(int j=1;j<=m;j++)
            {
                int head=1,tail=0;
                for(int i=n;i>=1;i--)
                {
                    if(s[i][j]=='x'){head=1,tail=0;continue;}
                    while(head<=tail&&q[head]-i>node[k].len) head++;
                    while(head<=tail&&f[pre][q[tail]][j]+q[tail]-i<=f[pre][i][j]) tail--;
                    q[++tail]=i;
                    f[now][i][j]=f[pre][q[head]][j]+q[head]-i;
                }
            }
        }
        else if(node[k].op==2)
        {
            for(int j=1;j<=m;j++)
            {
                int head=1,tail=0;
                for(int i=1;i<=n;i++)
                {
                    if(s[i][j]=='x'){head=1,tail=0;continue;}
                    while(head<=tail&&i-q[head]>node[k].len) head++;
                    while(head<=tail&&f[pre][q[tail]][j]+i-q[tail]<=f[pre][i][j]) tail--;
                    q[++tail]=i;
                    f[now][i][j]=f[pre][q[head]][j]+i-q[head];
                }
            }
        }
        else if(node[k].op==3)
        {
            for(int i=1;i<=n;i++)
            {
                int head=1,tail=0;
                for(int j=m;j>=1;j--)
                {
                    if(s[i][j]=='x') {head=1,tail=0;continue;}
                    while(head<=tail&&q[head]-j>node[k].len) head++;
                    while(head<=tail&&f[pre][i][q[tail]]+q[tail]-j<=f[pre][i][j]) tail--;
                    q[++tail]=j;
                    f[now][i][j]=f[pre][i][q[head]]+q[head]-j;
                }
            }
        }
        else 
        {
            for(int i=1;i<=n;i++)
            {
                int head=1,tail=0;
                for(int j=1;j<=m;j++)
                {
                    if(s[i][j]=='x') {head=1,tail=0;continue;}
                    while(head<=tail&&j-q[head]>node[k].len) head++;
                    while(head<=tail&&f[pre][i][q[tail]]+j-q[tail]<=f[pre][i][j]) tail--;
                    q[++tail]=j;
                    f[now][i][j]=f[pre][i][q[head]]+j-q[head];
                }
            }
        }
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            ans=max(ans,f[pre][i][j]);
    printf("%d\n",ans);
    return 0;
}

NOI2005 瑰丽华尔兹

原文:https://www.cnblogs.com/fengxunling/p/11004796.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!