子矩形 - 随机 - 二分

题目大意:
给一个每个位置有点权的网格,求点权和除以周长最大的子矩阵。 n 500 n\le500
题解:
考虑可以二分后做一个类似最大子矩阵的东西。
然后发现枚举上下边界可以放到前面枚举,然后再二分,这样把上下边界的枚举随机打乱然后每次判一下是否有可能比当前答案优即可,这样复杂度就是 O ( n 3 ) O(n^3) 了。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsinged lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
    int x=0,ch,s=0;while(((ch=gc)<'0'||ch>'9')&&ch!='-');
    if(ch^'-') x=ch^'0';else s=1;
    while((ch=gc)>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');
    return s?-x:x;
}
const int N=510;const db eps=1e-8,epsd=eps/10;
int a[N][N];lint s[N][N];
namespace subtask1{
    inline int brute_force10(int n)
    {
        db ans=INT_MIN;int is=0,js=0,ks=0,ts=0;
        rep(i,1,n) rep(j,1,n) rep(k,i,n) rep(t,j,n)
        {
            db v=((db)s[k][t]-s[i-1][t]-s[k][j-1]+s[i-1][j-1])/(k-i+1+t-j+1);
            if(v>ans) ans=v,is=i,js=j,ks=k,ts=t;
        }
        return !printf("%.9lf\n%d %d\n%d %d\n",(double)ans/2,is,js,ks,ts);
    }
}
namespace final_solution{
    db ps[N];int ls,rs,us,ds;
    inline int check(int u,int d,db x,int n)
    {
        rep(i,1,n) ps[i]=s[d][i]-s[u-1][i]-i*x;db v=0,ans=LLONG_MIN;
        rep(i,1,n) ans=max(ans,ps[i]-v),v=min(v,ps[i]);return ans-(d-u+1)*x>=0;
    }
    inline int getpos(int u,int d,db x,int n)
    {
        rep(i,1,n) ps[i]=s[d][i]-s[u-1][i]-i*x;
        db v=0,ans=LLONG_MIN;int l=0;
        rep(i,1,n)
        {
            if(ps[i]-v>ans) ans=ps[i]-v,ls=l+1,rs=i;
            if(ps[i]<v) v=ps[i],l=i;
        }
        return ans-2*(d-u+1)>=0;
    }
    pii lst[N*N];
    inline int acceptable_solution(int n)
    {
        int cnt=0;rep(i,1,n) rep(j,i,n) lst[++cnt]=mp(i,j);
        random_shuffle(lst+1,lst+cnt+1);db ans=INT_MIN;
        rep(i,1,cnt)
        {
            int u=lst[i].fir,d=lst[i].sec;
            if(!check(u,d,ans+eps,n)) continue;
            db L=ans,R=500.0*INT_MAX;us=u,ds=d;
            while(L+eps<R)
            {
                db mid=(L+R)/2;
                if(check(u,d,mid,n)) ans=mid,L=mid+epsd;
                else R=mid-epsd;
            }
        }
        getpos(us,ds,ans,n);
        return !printf("%.9lf\n%d %d\n%d %d\n",(double)ans/2,us,ls,ds,rs);
    }
}
int main()
{
//  freopen("data.in","r",stdin);
    int n=inn();
    rep(i,1,n) rep(j,1,n) a[i][j]=inn();
    rep(i,1,n) rep(j,1,n) s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];
    if(n<=100) return subtask1::brute_force10(n);
    return final_solution::acceptable_solution(n);
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/89335793