zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",ans);
        return 0;
    }
    
    
    
  • 相关阅读:
    vim操作
    git命令
    Python笔记(二)
    python笔记
    gdb笔记 ---《Linux.C编程一站式学习》
    python笔记——dict和set
    echo $?
    FastDFS与Nginx环境配置
    Nginx依赖库安装
    mixin多继承包装过程
  • 原文地址:https://www.cnblogs.com/fengxunling/p/11004796.html
Copyright © 2011-2022 走看看