6700. 【2020.06.07省选模拟】得分(score )
(File IO): input:score.in output:score.out
Time Limits: 1000 ms Memory Limits: 524288 KB Detailed Limits
Description
Input
Output
Sample Input
样例 1 输入: 3 4 3 10 1 1 8 样例 2 输入: 4 7 20 15 10 7 20 15 10
Sample Output
样例 1 输出: 0.62500000000 样例 2 输出: 0.31901840491
Data Constraint
Hint
题意:
给你n个二元组(a, t), 二元组的位置可以随意交换, T是所有t的总和。给出二元组i权值的计算方式bi = ai(1 - cxi/T)。
其中c是系数,xi是在一定的排列顺序下,i以及前面所有二元组的t值总和。求出最大的c, 使得 在sigma(bi) 最大的所有情况下,不存在排列中ai < a[j] 但, b[i] > b[j]。
思路:
通过推导,不难发现c的单调性。
于是二分。
发现那个最优排列满足a/t较大的放在前面,设k = a/t。
证明易。在排列中取两个位置i,j,讨论他们在排列中位置对答案贡献的区别,即证。
现在好像b已经确定了。
但是, 别忘了,对于k = k‘ , 我们可以在排列中交换两个二元组的位置。
所以,对于一个二元组,它实际上可能有多个不同的权值。
如图:
那怎么办呢?
考虑check函数。
我们要寻找ai < aj , bi > bj
那么可以以a为关键字排序,对于当前遍历到的一个二元组i, 检查是否前面有bj > bi。
因为我们要满足这个c在所有条件下都符合题意,所以,只需要判断bj max 是否 > bi min即可。
也就是维护一个前缀最大值,还有bimin bimax。
解。
trick:
提交即可。
#include<cstdio>
#include<algorithm>
#define sf scanf
#define mem(a, b) memset(a, b, sizeof(a))
#define open(x) freopen(x".in", "r", stdin);freopen(x".out", "w", stdout);
#define F(i, a, b) for(register ll i = a; i <= b ; i++)
#define Fd(i, a, b) for(register ll i = a; i >= b ; i--)
#define pf printf
#define mcy(a, b) memcpy(a, b, sizeof(a))
#define mod (ll)(1e9 + 7)
#define inf 2147483647
#define ll long long
#define N 200010
using namespace std;
inline ll in() {
ll x=0;
char ch = getchar(); ll f = 0;
while(ch < '0' || ch > '9') f |= ch == '-', ch = getchar();
while(ch >= '0' && ch <= '9') x = (x<<1) + (x<<3) + ch - '0', ch = getchar();
x = f ? -x : x;
return x;
}
struct node {
int a, t, minx, maxx;
double minb, maxb;
double key() {return (double)a / t;}
}d[N];
int n, T;
double ans;
bool cmp1 (node a, node b) {return a.key() > b.key();}
bool cmp2 (node a, node b) {return a.a < b.a;}
const double eps = 0.000000001;
int LAS[N], FIR[N];
int check(double c) {
F(i, 1, n) d[i].minb = (double)d[i].a * (1.00 - c * d[i].maxx / T), d[i].maxb = (double)d[i].a * (1.00 - c * d[i].minx / T);
double premax = 0;
F(i, 1, n) {
if(d[i].a == d[i - 1].a) {
i = FIR[i];
continue;
}
if(premax > d[i].minb) return 0;
premax = premax < d[i].maxb ? d[i].maxb : premax;
}
return 1;
}
void binary() {
double l = 0.00, r = 1.00;
while(r - l > eps){
double mid = (l + r) / 2.00;
if(check(mid)) {
ans = mid;
l = mid;
}else r = mid;
}
}
int time[N], las[N], fir[N];
void init() {
F(i, 1, n) time[i] = time[i - 1] + d[i].t;
F(i, 1, n) if(d[i].key() != d[i - 1].key()) fir[i] = i; else fir[i] = fir[i - 1];
Fd(i, n, 1) if(d[i].key() != d[i + 1].key()) las[i] = i; else las[i] = las[i + 1];
F(i, 1, n) d[i].minx = d[fir[i] - 1].maxx + d[i].t, d[i].maxx = time[las[i]];
}
int main() {
open("score");
n = in();
F(i, 1, n) d[i].a = in();
F(i, 1, n) d[i].t = in();
sort(d + 1, d + 1 + n, cmp1);
init();
sort(d + 1, d + 1 + n, cmp2);
T = time[n];
F(i, 1, n) if(d[i].a != d[i - 1].a) LAS[i] = i; else LAS[i] = LAS[i - 1];
Fd(i, n, 1) if(d[i].a != d[i + 1].a) FIR[i] = i; else FIR[i] = FIR[i + 1];
binary();
pf("%.10lf", ans);
return 0;
}