题目及数据![在这里插入图片描述](https://img-blog.csdnimg.cn/38695b455c5c476593ab41a7ce9fa7b8.png)
分析
看到这题目时,第一反应是——先把图建起来。然后很快发现,光建图就
1
e
10
1e10
1e10了。于是开始认真想。从建图的方式来看,行和列是分开来的。于是可以想到分开来求然后再合并求出最终的解。
然后看题目要我们求什么,连续子矩阵的最大平均值。因为我们通过行和列分开求的方式,所以这题就变成了求子序列的最大平均值。然后百度,发现有二分的写法,于是抄下来改了改。
double l=0.0,r=200000.0;
while(r-l>1e-8)
{
double mid=(l+r)/2.0;
for (ll i=1;i<=x;i++)
c[i]=c[i-1]+a[i]-mid;
double sum=c[x],mi=0.0;
for (ll i=x+1;i<=n;i++)
{
mi=min(mi,c[i-x]);
c[i]=c[i-1]+a[i]-mid;
sum=max(sum,c[i]-mi);
}
if (sum>=0) l=mid;
else r=mid;
}
return r;
过程就是把平均值二分,然后对序列
a
a
a减去
m
i
d
mid
mid后求最大的非负子序列的和。
因为平均值的关系,两次求得的值相加即可。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll a[1001200];
double c[1001020];
double solve(ll n,ll x)
{
for (ll i=1;i<=n;i++) scanf("%lld",&a[i]);
double l=0.0,r=200000.0;
while(r-l>1e-8)
{
double mid=(l+r)/2.0;
for (ll i=1;i<=x;i++)
c[i]=c[i-1]+a[i]-mid;
double sum=c[x],mi=0.0;
for (ll i=x+1;i<=n;i++)
{
mi=min(mi,c[i-x]);
c[i]=c[i-1]+a[i]-mid;
sum=max(sum,c[i]-mi);
}
if (sum>=0) l=mid;
else r=mid;
}
return r;
}
int main()
{
ll n,m,x,y;
scanf("%lld%lld%lld%lld",&n,&m,&x,&y);
printf("%.10lf\n",solve(n,x)+solve(m,y));
}
最后
二分因为分了两次,可以放函数里。放外面不着怎的WA了