题目大意
一个n*m的网格,每列从上往下选取至少一个,求平均值的最大值。
n*m<=100000
二分
遇到这种平均值都可以二分判定。
二分答案ans,然后所有元素减去ans,每行贪心的选取最大前缀和,然后加起来看是否非负即可。
对于n*m<=100000,如果像我那么SB就开个n根号的数组吧……
#include<cstdio>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
typedef double db;
const int maxn=100000+10,maxm=340+10;
const db eps=0.000001;
int a[maxn][maxm];
db b[maxn][maxm];
int i,j,k,t,n,m;
db l,r,mid,ans;
bool czy;
int read(){
int x=0;
char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x;
}
bool check(db ans){
int i,j;
db k,l,t=0;
fo(i,1,n)
fo(j,1,m){
if (czy) b[i][j]=(db)a[i][j]-ans;
else b[j][i]=(db)a[j][i]-ans;
}
fo(j,1,m){
l=k=(czy?b[1][j]:b[j][1]);
fo(i,2,n){
l+=(czy?b[i][j]:b[j][i]);
k=max(k,l);
}
t+=k;
}
return t>=eps;
}
int main(){
m=read();n=read();
if (n>m) czy=1;
fo(i,1,m)
fo(j,1,n){
t=read();
if (czy) a[j][i]=t;else a[i][j]=t;
}
l=1;r=1000000000;
while (r-l>=eps){
mid=(l+r)/2;
if (check(mid)) l=mid;else r=mid;
}
printf("%.4lf\n",l);
}