題目大意:給你一個$n\times n$的矩陣,請在這個矩陣中找出一個子矩陣$(x_1,y_1)$,$(x_2,y_2)$,使得$\dfrac{\sum\limits_{i=x_1}^{x_2} \sum\limits_{j=y_1}^{y_2}a[i][j] }{2\times(x_2-x_1+y_2-y_1)}$最大。c++
數據範圍:$n≤500$,$|A|≤10^9$dom
咱們考慮二分這個答案spa
設答案的分母爲$S$,分子爲$d$,當前二分到的數是$ans$。code
若是最終的答案能夠大於$ans$,則有$\frac{S}{d}>ans$blog
咱們移項,則有$S>2ans(\Delta x+\Delta y)$it
咱們考慮枚舉$\Delta x$,而後找出一個寬爲$x$,知足上面約束的子矩陣。class
令$F_x[i][j]=\sum\limits_{k=0}^{x-1} a[i+k][j]$im
對於$i∈[1,n-x+1]$,若在$F_x[i]$中找到知足條件的矩陣,那麼你會找到$j_1$和$j_2$,知足:數據
$ans\times x>\sum\limits_{j=j_1}^{j_2} (F_x[i][j]-ans)$di
簡單變式一下,則有:
$ans\times x>\sum\limits_{j=1}^{j_2}(F_x[i][j]-ans)-\sum\limits_{j=1}^{j_1-1}(F_x[i][j]-ans)$
咱們能夠經過維護$\sum\limits_{j=1}^{j_2}(F_x[i][j]-ans)$的最小值和最大值在$O(n^2)$的時間內,完成給定$\Delta x$和給定$ans$的判斷。
加上二分$ans$的過程,咱們能夠在$O(n^2log(-\epsilon))$的時間複雜度內,求出給定$\Delta x$狀況下的最大$ans$。
整個作法的複雜度也就是$O(n^3log(-\epsilon))$,顯然過不去。
咱們考慮到,一個長度爲$n$的隨機序列的最長上升子序列指望長度是$O(\log\ n)$的
咱們考慮將須要判斷的序列X隨機打亂。
咱們先將序列進行修改,而後基於以前求出的$ans$,求一遍答案,判斷修改後的序列是否會更加優秀。
若是更加優秀,咱們就從新二分出答案。
不難發現,從新二分答案的次數指望是$O(\log\ n)$的。
總的複雜度就是$O(n^3+n^2\log n\log(-\varepsilon))$的。
完結撒花
1 #include<bits/stdc++.h> 2 #define M 505 3 #define eps 1e-8 4 #define L long long 5 #define INF 3e14 6 #define _y1 orzmyh 7 using namespace std; 8 9 L a[M][M]={0}; 10 int p[M]={0},n; 11 12 int _x1,_x2,_y1,_y2; 13 int _X1,_X2,_Y1,_Y2; 14 bool check(int x,double ans){ 15 for(int i=1;i<=n-x+1;i++){ 16 double minn=0,now=0; int minid=0; 17 for(int j=1;j<=n;j++){ 18 now+=a[i+x-1][j]-a[i-1][j]-ans; 19 if(minn>now){ 20 minn=now; 21 minid=j; 22 } 23 if(now-minn>=ans*x){ 24 _x1=i; _x2=i+x-1; 25 _y1=minid+1; _y2=j; 26 return 1; 27 } 28 } 29 } 30 return 0; 31 } 32 bool ok(double l,double r){ 33 return (r-l>eps)&&(((r-l)/l)>eps); 34 } 35 36 int main(){ 37 // freopen("in.txt","r",stdin); 38 double ans=0,maxn=-INF; 39 scanf("%d",&n); 40 for(int i=1;i<=n;i++) 41 for(int j=1;j<=n;j++){ 42 scanf("%lld",&a[i][j]); 43 maxn=max(maxn,1.*a[i][j]); 44 } 45 if(maxn<=0){ 46 printf("%.10lf\n",maxn/4); 47 for(int i=1;i<=n;i++) 48 for(int j=1;j<=n;j++) 49 if(a[i][j]==maxn){ 50 printf("%d %d\n",i,j); 51 printf("%d %d\n",i,j); 52 return 0; 53 } 54 return 0; 55 } 56 for(int i=1;i<=n;i++) 57 for(int j=1;j<=n;j++) a[i][j]+=a[i-1][j]; 58 59 for(int i=1;i<=n;i++) p[i]=i; 60 random_shuffle(p+1,p+n+1); 61 62 63 for(int i=1;i<=n;i++){ 64 int x=p[i]; 65 if(!check(x,ans)) continue; 66 double l=ans,r=INF; 67 while(ok(l,r)){ 68 double mid=(l+r)/2.; 69 if(check(x,mid)) l=mid; 70 else r=mid; 71 } 72 ans=l; 73 _X1=_x1; _X2=_x2; 74 _Y1=_y1; _Y2=_y2; 75 } 76 printf("%.10lf\n",ans/2); 77 printf("%d %d\n",_X1,_Y1); 78 printf("%d %d\n",_X2,_Y2); 79 }