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;
}
posted @ 2020-05-27 15:50  源曲明  阅读(299)  评论(0编辑  收藏  举报