bzoj1723 [ Usaco2009 Feb ] --前缀和(水题)
题目大意:
你难以想象贝茜看到一只妖精在牧场出现时是多么的惊讶.她不是傻瓜,立即猛扑过去,用她那灵活的牛蹄抓住了那只妖精.
“你可以许一个愿望,傻大个儿!”妖精说.
“财富,”贝茜用梦游般的声音回答道, “我要获得财富的机会.”
妖精从来没有碰到过这么简单的愿望.他在地方划出一大块N×N(1≤N≤200)的方格,每个格子上写上_1,000,000到1,000,000之间的数字.他说: “在方格上朝一个方向行走,可以是行的方向,列的方向,斜对角的方向,一步只能走一格,所有你踩过的数字的和就是你的财富.”
贝茜请你来帮忙,找到一行、一列或一条对角线上找一段连续的数字,它们的和最大.由于妖精方格的神奇特性,沿着一个方向走,走到了边际,再一步跨过去可以“绕”到方格的对边出现.一行两端的格子是相邻的,一列两端的格子也是相邻的,甚至相邻两行的分别两端的格子也是相邻的(斜对角方向).
对于下图左边的方格,所有标记过的数字都在一条对角线上.
对于这个方格,能踩出来的最大的和是24,踩过的数字在右图中标记出来了
思路:
我们可以维护行、列、对角线的前缀和,每次用当前和减去最小和、总和减去最小和更新答案。
由于行、列、对角线互不影响,O(n^2)枚举就可以了。
代码:
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; #define N 201 inline char Nc(){ static char buf[100000],*p1=buf,*p2=buf; if(p1==p2){ p2=(p1=buf)+fread(buf,1,100000,stdin); if(p1==p2)return EOF; } return *p1++; } inline void Read(int& x){ char c=Nc(),b=1; for(;c<'0'||c>'9';c=Nc())if(c=='-')b=-1; for(x=0;c>='0'&&c<='9';x=(x<<3)+(x<<1)+c-48,c=Nc());x*=b; } int i,j,k,n,x[N][N],y[N][N],a[N][N],b[N][N],Ans=-1000000,Mix[N],Miy[N],Mia[N],Mib[N],Max[N],May[N],Maa[N],Mab[N]; int main() { Read(n); for(i=1;i<=n;i++) for(j=1;j<=n;j++){ Read(k); x[i][j]=x[i][j-1]+k; y[j][i]=y[j][i-1]+k; a[(i-j+n)%n+1][i]=a[(i-j+n)%n+1][i-1]+k; b[(i+j)%n+1][i]=b[(i+j)%n+1][i-1]+k; } for(i=1;i<=n;i++) for(j=1;j<=n;j++){ if(x[i][j]-Mix[i]>Ans)Ans=x[i][j]-Mix[i]; if(y[i][j]-Miy[i]>Ans)Ans=y[i][j]-Miy[i]; if(a[i][j]-Mia[i]>Ans)Ans=a[i][j]-Mia[i]; if(b[i][j]-Mib[i]>Ans)Ans=b[i][j]-Mib[i]; if(x[i][n]-x[i][j-1]+Max[i]>Ans)Ans=x[i][n]-x[i][j-1]+Max[i]; if(y[i][n]-y[i][j-1]+May[i]>Ans)Ans=y[i][n]-y[i][j-1]+May[i]; if(a[i][n]-a[i][j-1]+Maa[i]>Ans)Ans=a[i][n]-a[i][j-1]+Maa[i]; if(b[i][n]-b[i][j-1]+Mab[i]>Ans)Ans=b[i][n]-b[i][j-1]+Mab[i]; if(x[i][j]<Mix[i])Mix[i]=x[i][j]; if(y[i][j]<Miy[i])Miy[i]=y[i][j]; if(a[i][j]<Mia[i])Mia[i]=a[i][j]; if(b[i][j]<Mib[i])Mib[i]=b[i][j]; if(x[i][j]>Max[i])Max[i]=x[i][j]; if(y[i][j]>May[i])May[i]=y[i][j]; if(a[i][j]>Maa[i])Maa[i]=a[i][j]; if(b[i][j]>Mab[i])Mab[i]=b[i][j]; } printf("%d",Ans); return 0; }