APIO试题训练
APIO试题训练
BZOJ 1177:Oil
(果然我只会做套路题)
考虑3个块的位置,主要可以分为六种情况:

于是我们统计一下左上,右上,左下,右下的最大K*K的矩阵的最大值前缀和,再计算一下以每一行,每一列结尾的最大矩阵,直接枚举切割位置就可以了。
代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#define rep(i,x,y) for (int i=x;i<=y;i++)
#define dep(i,y,x) for (int i=y;i>=x;i--)
#define sz(x) (int)(x.size())
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
const int maxn=1500+7;
int n,m,K,ans,cur;
int a[maxn][maxn],s[maxn][maxn],lu[maxn][maxn],ru[maxn][maxn],ld[maxn][maxn],rd[maxn][maxn],col[maxn],row[maxn];
int calc(int x1,int y1,int x2,int y2)
{
return s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1];
}
void init()
{
rep(i,1,n)
{
s[i][0]=0;
rep(j,1,m) s[i][j]=s[i][j-1]+a[i][j];
}
rep(i,1,n) rep(j,1,m) s[i][j]+=s[i-1][j];
rep(i,K,n) rep(j,K,m) lu[i][j]=max(calc(i-K+1,j-K+1,i,j),max(lu[i-1][j],lu[i][j-1]));
rep(i,K,n) dep(j,m-K+1,1) ru[i][j]=max(calc(i-K+1,j,i,j+K-1),max(ru[i-1][j],ru[i][j+1]));
dep(i,n-K+1,1) rep(j,K,m) ld[i][j]=max(calc(i,j-K+1,i+K-1,j),max(ld[i+1][j],ld[i][j-1]));
dep(i,n-K+1,1) dep(j,m-K+1,1) rd[i][j]=max(calc(i,j,i+K-1,j+K-1),max(rd[i+1][j],rd[i][j+1]));
rep(i,K,n)
{
row[i]=0;
rep(j,K,m) row[i]=max(row[i],calc(i-K+1,j-K+1,i,j));
}
rep(j,K,m)
{
col[j]=0;
rep(i,K,m) col[j]=max(col[j],calc(i-K+1,j-K+1,i,j));
}
}
int main()
{
scanf("%d%d%d",&n,&m,&K);
rep(i,1,n) rep(j,1,m) scanf("%d",&a[i][j]);
init();
ans=0;
rep(i,K,n-K)
rep(j,K,m-K)
{
ans=max(ans,lu[i][j]+ru[i][j+1]+rd[i+1][1]);
ans=max(ans,lu[i][m]+ld[i+1][j]+rd[i+1][j+1]);
}
rep(j,K,m-K)
rep(i,K,n-K)
{
ans=max(ans,lu[i][j]+ld[i+1][j]+ru[n][j+1]);
ans=max(ans,lu[n][j]+ru[i][j+1]+rd[i+1][j+1]);
}
rep(i,K,n-2*K)
{
cur=0;
rep(j,i+K,n-K)
{
cur=max(cur,row[j]);
ans=max(ans,lu[i][m]+cur+ld[j+1][m]);
}
}
rep(i,K,m-2*K)
{
cur=0;
rep(j,i+K,m-K)
{
cur=max(cur,col[j]);
ans=max(ans,lu[n][i]+cur+ru[n][j+1]);
}
}
printf("%d\n",ans);
// system("pause");
return 0;
}

浙公网安备 33010602011771号