• LG3625 [APIO2009]采油区域(前缀和+DP)


    LG3625 [APIO2009]采油区域

    前言

    重复的思维,重复的代码,重复地调试。

    我已AC,感觉良好

    解法1

    没啥技巧,看一眼就知道怎么做了。

    分为 (6) 个情况,哪 (6) 种可以看别的大佬的 blog。这篇题解只要讲一下别的大佬没有仔细讲的预处理部分

    我们要处理出来的是 (7) 个量。见下:

    量: (sum_{i,j}) (lu_{i,j}) (ld_{i,j}) (ru_{i,j}) (rd_{i,j}) (ver_{i,j}) (hor_{i,j})
    含义: 左上角矩阵中数字的和 左上角最大 (k*k) 矩阵数字和 左下角最大 (k*k) 矩阵数字和 右上角最大 (k*k) 矩阵数字和 右下角最大 (k*k) 矩阵数字和 (i)(j) 列最大 (k*k) 矩阵数字和 (i)(j) 行最大 (k*k) 矩阵数字和

    我们要把每个量处理出来。(sum) 就是二维前缀和,用于计算后面 (6) 个量,(lu,ld,ru,rd) 四个量用 DP 求解。(ver,hor)区间 DP 求解。

    最后 (6) 种情况讨论一下即可。

    解法2

    两位神 @cookiebus @code_hunter 貌似有另一种解法,我没太看懂他们的代码。他们又没写题解,感兴趣的小伙伴可以去问一下。

    代码

    这代码,你不看也罢。反正你看了根没看差不多

    祝你好运!

    注意不要开 long long,会MLE!

    //Don't act like a loser.
    //This code is written by huayucaiji
    //You can only use the code for studying or finding mistakes
    //Or,you'll be punished by Sakyamuni!!!
    #include<bits/stdc++.h>
    using namespace std;
    
    int read() {
    	char ch=getchar();
    	int f=1,x=0;
    	while(ch<'0'||ch>'9') {
    		if(ch=='-')
    			f=-1;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9') {
    		x=x*10+ch-'0';
    		ch=getchar();
    	}
    	return f*x;
    }
    
    const int MAXN=15e2+10; 
    
    int n,m,k,ans;
    int sum[MAXN][MAXN],a[MAXN][MAXN];
    int lu[MAXN][MAXN],ld[MAXN][MAXN],rd[MAXN][MAXN],ru[MAXN][MAXN],hor[MAXN][MAXN],ver[MAXN][MAXN];
    
    int gets(int x,int y,int a,int b) {
    	return sum[a][b]+sum[x-1][y-1]-sum[x-1][b]-sum[a][y-1];
        //用 sum 计算一个子矩阵中的数字和
    }
    
    signed main() {
    	cin>>n>>m>>k;
    	for(int i=1;i<=n;i++) {
    		for(int j=1;j<=m;j++) {
    			a[i][j]=read();
    			sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
    		}
    	}
    	
    	for(int i=k;i<=n;i++) {
    		for(int j=k;j<=m;j++) {
    			lu[i][j]=max(max(lu[i][j-1],lu[i-1][j]),gets(i-k+1,j-k+1,i,j));
    		}
    	}
    	for(int i=k;i<=n;i++) {
    		for(int j=m-k+1;j;j--) {
    			ru[i][j]=max(max(ru[i][j+1],ru[i-1][j]),gets(i-k+1,j,i,j+k-1));
    		}
    	}
    	for(int i=n-k+1;i;i--) {
    		for(int j=1;j<=m;j++) {
    			ld[i][j]=max(max(ld[i][j-1],ld[i+1][j]),gets(i,j-k+1,i+k-1,j));
    		}
    	}
    	for(int i=n-k+1;i;i--) {
    		for(int j=m-k+1;j;j--) {
    			rd[i][j]=max(max(rd[i][j+1],rd[i+1][j]),gets(i,j,i+k-1,j+k-1));
    		}
    	}
    	for(int i=1;i<=n-k+1;i++) {
    		for(int j=1;j<=m-k+1;j++) {
    			hor[i][i+k-1]=max(hor[i][i+k-1],gets(i,j,i+k-1,j+k-1));
    		}
    	}
    	for(int len=k+1;len<=n;len++) {
    		for(int i=1,j=i+len-1;j<=n;j++,i++) {
    			hor[i][j]=max(hor[i+1][j],hor[i][j-1]);
    		}
    	}
    	for(int i=1;i<=m-k+1;i++) {
    		for(int j=1;j<=n-k+1;j++) {
    			ver[i][i+k-1]=max(ver[i][i+k-1],gets(j,i,j+k-1,i+k-1));
    		}
    	}
    	for(int len=k+1;len<=m;len++) {
    		for(int i=1,j=i+len-1;j<=m;j++,i++) {
    			ver[i][j]=max(ver[i+1][j],ver[i][j-1]);
    		}
    	}
        //预处理
    	
    	for(int i=1;i<=n;i++) {
    		for(int j=1;j<=m;j++) {
    			ans=max(ans,hor[i+1][n]+lu[i][j]+ru[i][j+1]);
    			ans=max(ans,hor[1][i]+ld[i+1][j]+rd[i+1][j+1]);
    			ans=max(ans,ver[j+1][m]+lu[i][j]+ld[i+1][j]);
    			ans=max(ans,ver[1][j]+ru[i][j+1]+rd[i+1][j+1]);
    		}
    	}
    	for(int i=1;i<=n;i++) {
    		for(int j=i+1;j<=n;j++) {
    			ans=max(ans,hor[1][i]+hor[i+1][j]+hor[j+1][n]);
    		}
    	}
    	for(int i=1;i<=m;i++) {
    		for(int j=1;j<=m;j++) {
    			ans=max(ans,ver[1][i]+ver[i+1][j]+ver[j+1][m]);
    		}
    	}
        //计算答案
    	
    	cout<<ans<<endl;
    	return 0;
    }
    
  • 相关阅读:
    (转)Golang reflect.DeepEqual函数:判断两个值是否一致
    Kubernetes字段Finalizers
    校园电子屏无人值守模式探索
    史上最全测试开发工具推荐(含自动化、性能、稳定性、抓包)
    Java 将Word转为HTML的方法
    C# 在PPT中添加数学公式
    C# 将PPT转为OFD/DPT/DPS/ODP/POTX/UOP
    C# 将Excel转为OFD、UOS
    Java 扫描识别条形码图片
    C# 加载Word的3种方法
  • 原文地址:https://www.cnblogs.com/huayucaiji/p/LG3625.html
Copyright © 2020-2023  润新知