AGC028F(dp)
神仙题,myhTQL
记\(f_{i,j}\)表示\((i,j)\)能够到达的点集的数值之和,转移显然有\(f_{i,j}=a_{i,j}+f_{i+1,j}+f_{i,j+1}\)
然后考虑如果\((i+1,j)\)和\((i,j+1)\)都是可达的,那么我们要怎么减去重复的部分
记\(mn_{i,j,k}\)和\(mx_{i,j,k}\)表示\((i,j)\)能到达的点中,第\(k\)行纵坐标最小和最大的,如果\((i,j+1)\)和\((i+1,j)\)都能到达第\(k\)行,显然有\(mn_{i+1,j,k}\leq mn_{i,j+1,k},mx_{i+1,j,k}\leq mx_{i,j+1,k}\)
而如果\((i+1,j)\)和\((i,j+1)\)在第\(k\)行有交,那么\((k,mn_{i,j+1,k})\)必然在其中,而且两个点都能到达的点是若干个\(mn_{i,j+1,k}\)的可达点集的并,可以\(O(n)\)计算
总复杂度\(O(n^3)\)
//yuanquming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
typedef long long ll;
const int N=1505;
char s[N];int a[N][N],f[N][N],rpos[N][N],mn[2][N][N],mx[2][N][N],n,t;
ll res;
int main(){
// freopen("testdata.in","r",stdin);
scanf("%d",&n);
fp(i,1,n){
scanf("%s",s+1);
fp(j,1,n)a[i][j]=s[j]=='#'?0:s[j]-'0';
}
fd(i,n,1){
fd(j,n,1)if(a[i][j]){
f[i][j]=f[i+1][j]+f[i][j+1]+a[i][j];
rpos[i][j]=max({rpos[i+1][j],rpos[i][j+1],i});
mn[t][j][i]=j;
fp(k,i+1,rpos[i+1][j])mn[t][j][k]=mn[t^1][j][k];
fp(k,max(rpos[i+1][j],i)+1,rpos[i][j+1])mn[t][j][k]=mn[t][j+1][k];
mx[t][j][i]=j;
fp(k,i,rpos[i][j+1])mx[t][j][k]=mx[t][j+1][k];
fp(k,max(rpos[i][j+1],i)+1,rpos[i+1][j])mx[t][j][k]=mx[t^1][j][k];
int d=i+1,r=min(rpos[i+1][j],rpos[i][j+1]);
while(d<=r){
if(mx[t^1][j][d]>=mn[t][j+1][d]){
f[i][j]-=f[d][mn[t][j+1][d]];
d=rpos[d][mn[t][j+1][d]];
}
++d;
}
res+=1ll*a[i][j]*(f[i][j]-a[i][j]);
}
t^=1;
}
printf("%lld\n",res);
return 0;
}