P1398 [NOI2013] 書法家

rgw2010發表於2024-07-31

思路:

來一篇極小常數的 \(O(N^3M)\)\(O(N^2M \log^2 N)\) 的題解,最慢點在 500ms 以下但是為什麼還是最劣解

定義 \(dp_{i,j,k,x \in \{0,1,2\},y \in \{0,1,2\}}\) 表示對於正在畫的第 \(x\) 個字元,目前正在畫開頭/中間/結尾,且當前畫的矩形的右下角是 \((i,j)\) 和右上角 \((k,j)\)

則狀態轉移方程為,為了使式子不過於太醜陋,分段函式就表示取 \(\max\)

\[dp_{i,j,k,0,0} = \begin{cases} \sum\limits_{I=k}^i a_{I,j} \\ \sum\limits_{I=k}^i a_{I,j} + dp_{i,j-1,k} \end{cases} \]

\[dp_{i,j,k,0,1} = \sum\limits_{I=k}^i a_{I,j} + \begin{cases} \max\limits_{l=i+1}^n dp_{l,j-1,k,0,0} \\ \max\limits_{x=k}^i \max\limits_{y=1}^k dp_{x,j-1,y,0,1} \\ \max\limits_{y=1}^{k-1} dp_{k-1,j-1,y} \end{cases} \]

\[dp_{i,j,k,0,2} = \sum\limits_{I=k}^i a_{I,j} + \begin{cases} \max\limits_{l=k+1}^i dp_{i,j-1,l,0,1} \\ dp_{i,j-1,k,0,2} \end{cases} \]

\[dp_{i,j,k,1,0} = \sum\limits_{I=k}^i a_{I,j} + \max\limits_{x=1}^n \max\limits_{z=1}^{k-2} \max\limits_{y=1}^i dp_{i,z,y,0,2} \]

\[dp_{i,j,k,1,1} = a_{k,j} + a_{i,j} + \begin{cases} dp_{i,j-1,k,1,0} \\ dp_{i,j-1,k,1,1} \end{cases} \]

\[dp_{i,j,k,1,2} = \sum\limits_{I=k}^i a_{I,j} + dp_{i,j-1,k,1,1} \]

\[dp_{i,j,k,2,0} = a_{k,j} + a_{i,j} + \begin{cases} dp_{i,j-1,k,2,0} \\ \max\limits_{x=1}^n \max\limits_{z=1}^{k-2} \max\limits_{y=1}^i dp_{i,z,y,1,2} \end{cases} \]

\[dp_{i,j,k,2,1} = \sum\limits_{I=k}^i a_{I,j} + \begin{cases} dp_{i,j-1,k,2,0} \\ dp_{i,j-1,k,2,1}\end{cases} \]

\[dp_{i,j,k,2,2} = a_{k,j} + a_{i,j} + \begin{cases} dp_{i,j-1,k,2,1} \\ dp_{i,j-1,k,2,2} \end{cases} \]

對於一重迴圈部分,可以直接字首/字尾預處理 \(\max\);對於查詢矩陣最大值部分,可以用二維 ST 表或者暴力掃一維然後預處理另外一維的字首/字尾 \(\max\)

時間複雜度為 \(O(N^3M)\)\(O(N^2M \log^2 N)\),由於感覺二維 ST 表可能快不了多少,於是沒有寫,有興趣的讀者可以自己嘗試一下。

空間可能開不下,要用滾動陣列最佳化。

完整程式碼:

#include<bits/stdc++.h>
#define Add(x,y) (x+y>=mod)?(x+y-mod):(x+y)
#define lowbit(x) x&(-x)
#define pi pair<ll,ll>
#define pii pair<ll,pair<ll,ll>>
#define iip pair<pair<ll,ll>,ll>
#define ppii pair<pair<ll,ll>,pair<ll,ll>>
#define fi first
#define se second
#define full(l,r,x) for(auto it=l;it!=r;it++) (*it)=x
#define Full(a) memset(a,0,sizeof(a))
#define open(s1,s2) freopen(s1,"r",stdin),freopen(s2,"w",stdout);
using namespace std;
typedef double db;
typedef unsigned long long ull;
typedef int ll;
bool Begin;
const ll N=155,M=505,INF=1e9; 
inline ll read(){
    ll x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-')
          f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=(x<<1)+(x<<3)+(c^48);
        c=getchar();
    }
    return x*f;
}
inline void write(ll x){
	if(x<0){
		putchar('-');
		x=-x;
	}
	if(x>9)
	  write(x/10);
	putchar(x%10+'0');
}
ll n,m,ans=-INF;
ll a[N][M],s[N][M];
ll dp[2][N][M][N];
ll MAX[M][2],T1[N][M],T2[N][M][N],T3[N][M][N],T4[N][M][N];
bool End;
int main(){
//	open("A.in","A.out");
	memset(T1,-0x7f,sizeof(T1));
	memset(T2,-0x7f,sizeof(T2));
	memset(T3,-0x7f,sizeof(T3));
	memset(T4,-0x7f,sizeof(T4));
	memset(MAX,-0x7f,sizeof(MAX));
	memset(dp,-0x7f,sizeof(dp));
	n=read(),m=read();
	for(int i=1;i<=n;i++)
	  for(int j=1;j<=m;j++)
		a[i][j]=read();
	for(int i=1;i<=n;i++)
	  for(int j=1;j<=m;j++)
		s[i][j]=s[i-1][j]+a[i][j];
	for(int i=1;i<=n;i++)
	  for(int j=1;j<=m;j++)
		for(int k=1;k<=i-1;k++)
		  dp[0][i][j][k]=s[i][j]-s[k-1][j]+max(dp[0][i][j-1][k],0);
	for(int j=1;j<=m;j++){
	    for(int i=n;i>=1;i--){
	    	for(int k=1;k<=i;k++){
	    		dp[1][i][j][k]=max(T1[k-1][j-1],T2[i+1][j-1][k]);
		    	for(int x=k;x<=i;x++)
		    	  dp[1][i][j][k]=max(dp[1][i][j][k],T3[x][j-1][k]);
		    	dp[1][i][j][k]+=s[i][j]-s[k-1][j];  
		    	T1[i][j]=max(T1[i][j],dp[1][i][j][k]);
		    	T2[i][j][k]=max(T2[i+1][j][k],dp[0][i][j][k]);
		    	T3[i][j][k]=max(T3[i][j][k-1],dp[1][i][j][k]);
			}
		}
	}
	memset(dp[0],-0x7f,sizeof(dp[0]));
	for(int j=1;j<=m;j++){
	    for(int i=1;i<=n;i++){
	    	ll M=-INF;
	    	for(int k=i-1;k>=1;k--){
	    		M=max(M,dp[1][i][j-1][k+1]);
	    		dp[0][i][j][k]=M;
			    dp[0][i][j][k]=max(dp[0][i][j][k],dp[0][i][j-1][k]);
			    dp[0][i][j][k]+=s[i][j]-s[k-1][j];
			    MAX[j][0]=max({MAX[j][0],MAX[j-1][0],dp[0][i][j][k]});
			}
		}
	}
	memset(dp[1],-0x7f,sizeof(dp[1]));
	for(int j=5;j<=m;j++)
	  for(int i=1;i<=n;i++)  
	    for(int k=1;k<=i-2;k++)
	      dp[1][i][j][k]=s[i][j]-s[k-1][j]+MAX[j-2][0];
	memset(dp[0],-0x7f,sizeof(dp[0]));
	for(int j=6;j<=m;j++)
	  for(int i=1;i<=n;i++)
	    for(int k=1;k<=i-2;k++)
	      dp[0][i][j][k]=a[k][j]+a[i][j]+max(dp[1][i][j-1][k],dp[0][i][j-1][k]);
	memset(dp[1],-0x7f,sizeof(dp[1]));
	for(int j=7;j<=m;j++){
	    for(int i=1;i<=n;i++){
		    for(int k=1;k<=i-2;k++){
		    	dp[1][i][j][k]=s[i][j]-s[k-1][j]+dp[0][i][j-1][k];	
		    	MAX[j][1]=max({MAX[j][1],MAX[j-1][1],dp[1][i][j][k]});
			} 
		}
	}
	memset(dp[0],-0x7f,sizeof(dp[0]));
	for(int j=9;j<=m;j++)
	  for(int i=1;i<=n;i++)
		for(int k=1;k<=i-2;k++)
		  dp[0][i][j][k]=a[k][j]+a[i][j]+max(dp[0][i][j-1][k],MAX[j-2][1]);
	memset(dp[1],-0x7f,sizeof(dp[1]));
	for(int j=10;j<=m;j++)
	  for(int i=1;i<=n;i++)
		for(int k=1;k<=i-2;k++)
		  dp[1][i][j][k]=s[i][j]-s[k-1][j]+max(dp[0][i][j-1][k],dp[1][i][j-1][k]);
	memset(dp[0],-0x7f,sizeof(dp[0]));
	for(int j=11;j<=m;j++){
	    for(int i=1;i<=n;i++){
		    for(int k=1;k<=i-2;k++){
		    	dp[0][i][j][k]=a[k][j]+a[i][j]+max(dp[1][i][j-1][k],dp[0][i][j-1][k]);
		    	ans=max(ans,dp[0][i][j][k]);
			}
		}
	}
	write(ans);
	cerr<<'\n'<<abs(&Begin-&End)/1048576<<"MB";
	return 0;
}

相關文章