6700. 【2020.06.07省选模拟】得分(score )

5 篇文章 0 订阅
4 篇文章 0 订阅

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;
} 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值