[题解]洛谷P4653
原题链
大体算法
我们可以发现,点亮权值越大的灯泡一定比点亮权值小的灯泡优(显然),所以我们肯定从最大的开始连续地取,那么我们先将权值从大到小排个序,接下来先考虑暴力算法,就是枚举(a)数组取到第(i)位,(b)数组取到第(j)位,并且暴力统计答案,这是我们发现每次统计到第(i)或(j)为其实就是(a.b)数组的前缀和,这样我们就可以优化一下,但仍然不是满分
接着我们想,由于最终的答案是取(a.b)两组的最小值,所以如果(a)数组的答案和(b)数组的答案这两个答案差距太大显然是不优的,因为反正是取最小值,所以不如把大的那部分少取一点,花费还更少,其实我们已将正解得出:那就是(a.b)数组的两个答案应该要尽量的接近,所以分两次做,其实也是暴力,第一次从(1~n)枚举(a)数组的前缀和(suma[i]),并用(lower_bound)查询比(suma[i])大的最小的(sumb[j]),并统计答案,再暴力枚举(sumb)即可.
代码
#include <bits/stdc++.h>
using namespace std;
double a[1000010],b[1000010];
double suma[1000010],sumb[1000010];
bool cmp(double x,double y){
return x > y;
}
int main(){
freopen("coin.in","r",stdin);
freopen("coin.out","w",stdout);
int n;
scanf("%d",&n);
for(int i = 1;i <= n;i++)
cin>>a[i];
for(int i = 1;i <= n;i++)
cin>>b[i];
sort(a + 1,a + n + 1,cmp);sort(b + 1,b + n + 1,cmp);
suma[1] = a[1];sumb[1] = b[1];
for(int i = 2;i <= n;i++){
suma[i] = a[i];
sumb[i] = b[i];
suma[i] += suma[i - 1];
sumb[i] += sumb[i - 1];
}
double ans1 = 0.0,ans2 = 0.0;
for(int i = 1;i <= n;i++){
int tmp1 = suma[i];
int p = lower_bound(sumb + 1,sumb + n + 1,tmp1) - sumb;
ans1 = max(ans1,min(suma[i],sumb[p]) - i - p);
}
for(int i = 1;i <= n;i++){
int tmp1 = sumb[i];
int p = lower_bound(suma + 1,suma + n + 1,tmp1) - suma;
ans2 = max(ans2,min(sumb[i],suma[p]) - i - p);
}
printf("%.4lf
",max(ans1,ans2));
return 0;
}