zoukankan      html  css  js  c++  java
  • 【 2019北京集训测试赛(十)】 子矩阵 二分

    题目大意:给你一个$n imes n$的矩阵,请在这个矩阵中找出一个子矩阵$(x_1,y_1)$,$(x_2,y_2)$,使得$dfrac{sumlimits_{i=x_1}^{x_2} sumlimits_{j=y_1}^{y_2}a[i][j] }{2 imes(x_2-x_1+y_2-y_1)}$最大。

    数据范围:$n≤500$,$|A|≤10^9$

    我们考虑二分这个答案

    设答案的分母为$S$,分子为$d$,当前二分到的数是$ans$。

    如果最终的答案可以大于$ans$,则有$frac{S}{d}>ans$

    我们移项,则有$S>2ans(Delta x+Delta y)$

    我们考虑枚举$Delta x$,然后找出一个宽为$x$,满足上面约束的子矩阵。

    令$F_x[i][j]=sumlimits_{k=0}^{x-1} a[i+k][j]$

    对于$i∈[1,n-x+1]$,若在$F_x[i]$中找到满足条件的矩阵,那么你会找到$j_1$和$j_2$,满足:

    $ans imes x>sumlimits_{j=j_1}^{j_2} (F_x[i][j]-ans)$

    简单变式一下,则有:

    $ans imes x>sumlimits_{j=1}^{j_2}(F_x[i][j]-ans)-sumlimits_{j=1}^{j_1-1}(F_x[i][j]-ans)$

    我们可以通过维护$sumlimits_{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^2log nlog(-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
    ",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
    ",i,j);
    51             printf("%d %d
    ",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
    ",ans/2);
    77     printf("%d %d
    ",_X1,_Y1);
    78     printf("%d %d
    ",_X2,_Y2);
    79 }
  • 相关阅读:
    MySQL架构备份
    MySQL物理备份 xtrabackup
    MySQL物理备份 lvm-snapshot
    MySQL逻辑备份mysqldump
    MySQL逻辑备份into outfile
    MySQ数据备份
    前端基础-- HTML
    奇淫异巧之 PHP 后门
    php中代码执行&&命令执行函数
    windows进程中的内存结构(缓冲溢出原理)
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/10710494.html
Copyright © 2011-2022 走看看