95pts..........
做法:
观察发现每个路径都可以对应到底部的一个点,且底部每个点都只对应一条路径。 。
对于底部每个点,O(n) 预处理该点路径的点权和,以及所涉及哪些直线,将其解析式记录。
然后枚举底部两个点,将其对应路径点权和相加,并通过小学数学求直线交点的方式减去重合部分。
O(n2)
#include <bits/stdc++.h>
using namespace std;
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define REP(i,a,b) for(int i=a;i>=b;i--)
typedef long long ll;
template<class T>
void ckmx(T& a,T b) {
a=max(a,b);
}
template<class T>
void ckmn(T& a,T b) {
a=min(a,b);
}
const int maxn=1005;
int n;
int a[maxn][maxn];
int flval[maxn];// 底部向左,右的值综合
struct Line {
int k,b;
int get(Line& l2) {
// 求交点的值
int k2=l2.k,b2=l2.b;
if(k==k2)return 0;
int x=(b2-b)/(k-k2);
if(x<0||x>n)return 0;
// printf("%dx+%d with %dx+%d\n",k,b,k2,b2);
if(x*(k-k2)==(b2-b)) {
int y=k*x+b;
// puts("ok");
if(y<=n)
return a[x][y];
return 0;
} else {
return 0;
}
}
} lefup,rigup,flup;
Line mkli(int x1,int y1,int x2,int y2) {
int k=(y2-y1)/(x2-x1);
// kx1+b=y1
// kx1=y1-b
// b+kx1=y1
// b= (y1-kx1)
int b=y1-k*x1;
Line res;
res.k=k;
res.b=b;
return res;
}
vector<Line> f[maxn];
int un(int i,int j) {
int ans=0;
for(auto u:f[i]) {
for(auto v:f[j]) {
ans+=u.get(v);
}
}
return ans;
}
int tmp[maxn];
int main() {
scanf("%d",&n);
FOR(i,1,n) {
FOR(j,1,n) {
scanf("%d",&a[i][j]);
}
}
FOR(j,1,n){
FOR(i,1,n){
tmp[n-i+1]=a[i][j];
}
FOR(i,1,n){
a[i][j]=tmp[i];
}
}
f[1].emplace_back(mkli(1,1,n,n));
int hang=1,lie=1;
while(hang<=n){
flval[1]+=a[hang][lie];
hang++;
lie++;
}
f[n].emplace_back(mkli(1,n,n,1));
hang=1,lie=n;
while(hang<=n){
flval[n]+=a[hang][lie];
hang++;
lie--;
}
// printf("%d %d\n",flval[1],flval[n]);
FOR(i,2,n-1) {
// printf("i = %d\n",i);
// 计算到左部/右部,之后的坐标
int y_lef=i;
int y_rig=n-i+1;
// printf("%d %d\n",y_lef,y_rig);
f[i].emplace_back(mkli(1,i,y_lef,1));
f[i].emplace_back(mkli(1,i,y_rig,n));
int hang=1,lie=i;
while(hang!=y_lef) {
flval[i]+=a[hang][lie];
hang++;
lie--;
}
flval[i]+=a[hang][lie];
// printf("current = %d\n",flval[i]);
int hang2=1,lie2=i;
while(hang2!=y_rig) {
hang2++;
lie2++;
flval[i]+=a[hang2][lie2];
}
// printf("current = %d\n",flval[i]);
// printf("hang %d %d hang2 %d %d\n",hang,lie,hang2,lie2);
int hang3=hang,lie3=lie;
while(hang3!=n) {
hang3++;
lie3++;
flval[i]+=a[hang3][lie3];
}
// printf("current = %d\n",flval[i]);
f[i].emplace_back(mkli(hang,lie,hang3,lie3));
int hang4=hang2,lie4=lie2;
while(hang4!=n) {
hang4++;
lie4--;
flval[i]+=a[hang4][lie4];
}
flval[i]-=a[hang4][lie4];
// printf("current = %d\n",flval[i]);
f[i].emplace_back(mkli(hang2,lie2,hang4,lie4));
assert(flval[i]>=0);
}
// puts("???");
int ans=0;
FOR(i,1,n) {
FOR(j,i+1,n) {
ckmx(ans,flval[i]+flval[j]-un(i,j));
// printf("i = %d j = %d ans = %d %d f = %d\n",i,j,flval[i],flval[j],un(i,j));
}
}
printf("%d\n",ans);
return 0;
}