NOI2005 瑰丽华尔兹

题目链接:戳我

先化简一下题意:一共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;
}


posted @ 2019-06-15 20:32  风浔凌  阅读(218)  评论(1编辑  收藏  举报