[APIO2009]采油區域
阿新 • • 發佈:2018-05-12
spa 繼續 HR note pac n-k span const 子矩陣 表示前\(j\)列中的最優矩陣\(S\)值
那麽有\(f[i][j]=max(upmx,lfmx[j-k])+S[i][j]\)
最巧妙的地方,我們最多可以選擇3個矩陣,那麽是不是可以看做選一個\(f[t1][t2]\)加上一個\(S[i][j]\)?
\(upmx\)表示當前點可轉移的上方所有點對應值\(f\)最優值。\(lfmx[j]\)表示前\(j\)列中的最優矩陣\(f\)值
那麽有\(ans[i][j]=max(upmx,lfmx[j-k])+S[i][j]\)
https://zybuluo.com/ysner/note/1144701
題面
給出一個\(n×m\)的矩陣。請在其中選擇\(3\)個互不相交的,大小恰為\(k×k\) 的子矩陣,使得子矩陣的權值和最大。
\(n\leq1500,m\leq1500\)
解析
這題和CJOJ2501很像呢。。。
看到題,本能地打了一個\(DP\),然後至今調不出來。。。
解法一
矩陣對應端點為其右下方端點,\(S[i][j]\)即為其面積。
\(f[i][j]\)表示選擇\((i,j)\)這個點對應矩陣,並且還選擇\(1~0\)個矩陣的最優解。
\(upmx\)表示當前點可轉移的上方所有點對應值\(S\)最優值。\(lfmx[j]\)
那麽有\(f[i][j]=max(upmx,lfmx[j-k])+S[i][j]\)
最巧妙的地方,我們最多可以選擇3個矩陣,那麽是不是可以看做選一個\(f[t1][t2]\)加上一個\(S[i][j]\)?
\(upmx\)表示當前點可轉移的上方所有點對應值\(f\)最優值。\(lfmx[j]\)表示前\(j\)列中的最優矩陣\(f\)值
那麽有\(ans[i][j]=max(upmx,lfmx[j-k])+S[i][j]\)
il void Matrix() { fp(i,1,n) fp(j,1,m) a[i][j]=gi()+a[i-1][j]+a[i][j-1]-a[i-1][j-1];//二維前綴和套路 fp(i,k,n) fp(j,k,m) s[i][j]=a[i][j]+a[i-k][j-k]-a[i-k][j]-a[i][j-k];//以(i,j)為右下端點的k*k矩陣的面積(還是套路,自己畫圖就知道了) } il void Solve() { upmx=0;memset(lfmx,0,sizeof(lfmx)); fp(i,k,n) { fp(j,k,m) upmx=max(upmx,s[i-k][j]);//i代表行,j代表列,該矩陣上面 底最下到該矩形的上邊的矩形 fp(j,k,m) { lfmx[j]=max(lfmx[j-1],lfmx[j]);//維護左邊的最大權值矩形 lfmx[j]=max(lfmx[j],s[i][j]);//維護上邊的最大權值矩形 f[i][j]=max(upmx,lfmx[j-k])+s[i][j];//累計合法情況 } }//搞完兩個矩陣的情況 upmx=0;memset(lfmx,0,sizeof(lfmx));//lfmx變成維護f,f代表兩個矩形,我們依據上面的套路繼續選取s(1個)+f(2個) fp(i,k,n) { fp(j,k,m) upmx=max(upmx,f[i-k][j]); fp(j,k,m) { lfmx[j]=max(lfmx[j-1],lfmx[j]); lfmx[j]=max(lfmx[j],f[i][j]); ans=max(ans,max(upmx,lfmx[j-k])+s[i][j]); } }//搞完三個矩陣的矩陣 //最後補充一句,在當前矩陣左上方選取的矩陣對當前矩陣沒有影響 } int main() { n=gi();m=gi();k=gi(); Matrix(); ans=0; Solve(); printf("%d\n",ans); return 0; }
解法二
取三個互不相交的矩形?
何嘗不是把整個圖形分為三塊,然後在每一塊中取最大值?
分成三塊有六種情況:
於是對應維護以每個點為右下角的\(k*k\)矩形權值和。
據此,可以維護每個點左上\(a\)、左下\(c\)、右上\(b\)、右下\(d\)部分的權值和。
然後枚舉中間點(兩條直線的交線,或者中間矩形的右下角),不斷取\(max\)統計即可。
// luogu-judger-enable-o2 #include<iostream> #include<cmath> #include<cstring> #include<cstdio> #include<cstdlib> #include<algorithm> #define ll long long #define re register #define il inline #define max(a,b) (a>b?a:b) #define min(a,b) (a<b?a:b) #define fp(i,a,b) for(re int i=a;i<=b;i++) #define fq(i,a,b) for(re int i=a;i>=b;i--) using namespace std; const int N=2100; int n,m,k,mp[N][N],a[N][N],b[N][N],c[N][N],d[N][N],ans; il int gi() { re int x=0,t=1; re char ch=getchar(); while((ch<‘0‘||ch>‘9‘)&&ch!=‘-‘) ch=getchar(); if(ch==‘-‘) t=-1,ch=getchar(); while(ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-48,ch=getchar(); return x*t; } int main() { n=gi();m=gi();k=gi(); fp(i,1,n) fp(j,1,m) mp[i][j]=mp[i-1][j]+mp[i][j-1]-mp[i-1][j-1]+gi(); fq(i,n,k) fq(j,m,k) mp[i][j]-=(mp[i-k][j]+mp[i][j-k]-mp[i-k][j-k]); fp(i,k,n) fp(j,k,m) a[i][j]=max(mp[i][j],max(a[i-1][j],a[i][j-1])); fp(i,k,n) fq(j,m,k) b[i][j]=max(mp[i][j],max(b[i-1][j],b[i][j+1])); fq(i,n,k) fp(j,k,m) c[i][j]=max(mp[i][j],max(c[i+1][j],c[i][j-1])); fq(i,n,k) fq(j,m,k) d[i][j]=max(mp[i][j],max(d[i+1][j],d[i][j+1])); fp(i,k,n-k) fp(j,k,m-k) ans=max(ans,a[i][m]+c[i+k][j]+d[i+k][j+k]); fp(i,k,n-k) fp(j,k,m-k) ans=max(ans,a[i][j]+b[i][j+k]+c[i+k][m]); fp(i,k,n-k) fp(j,k,m-k) ans=max(ans,a[n][j]+b[i][j+k]+d[i+k][j+k]); fp(i,k,n-k) fp(j,k,m-k) ans=max(ans,a[i][j]+b[n][j+k]+c[i+k][j]); fp(i,k,n-k) fp(j,k+k,m-k) ans=max(ans,a[n][j-k]+b[n][j+k]+mp[i][j]); fp(i,k+k,n-k) fp(j,k,m-k) ans=max(ans,a[i-k][m]+c[i+k][m]+mp[i][j]); printf("%d\n",ans); return 0; }
[APIO2009]采油區域