【蹦极】题解

题目描述

Alice \text{Alice} Alice 制作了 n n n 个人偶,编号为 1 1 1 n n n,并决定用这些人偶来表演蹦极,她又制作了一个蹦极台,这个蹦极台有 k k k 个不同的高度可供选择,分别是 h , 2 × h , ⋯   , k × h h,2\times h,\cdots,k\times h h,2×h,,k×h,注意,每个高度上只能站一个人偶,人偶都是独一无二的,她们也无法同时在两个高度表演。

Alice \text{Alice} Alice 制作的这 n n n 个人偶并不完全相同,至少他们的强度 w i w_i wi 是不一定相同的,如果有一个强度较低的人偶发现另一个强度较高的人偶在更低的地方表演蹦极,她就会非常不满,拒绝蹦极。(是的,自律人性 : P \text{P} P)此外,这些人偶都是会飞行的,因此她们要求完全由自己爬上蹦极位置,不需要 Alice \text{Alice} Alice 的帮助。一开始,所有的人偶都在一起,如果一个人偶的飞行速度是 v i v_i vi,她要爬上高度为 H H H 的地方蹦极需要 H / v i H/v_i H/vi 秒,所有人偶会同时开始向目标飞行。

为了让 Mukyu \text{Mukyu} Mukyu 观看时人偶们就位所用的时间最少, Alice \text{Alice} Alice 设计了一种方案来安排 n n n 个人偶中的其中 k k k 个表演蹦极。经历过上次梭哈题目后, Alice \text{Alice} Alice 现在对现代科技非常不屑,她认为现代科技无法完美的完成这一任务。显然,你的任务就是证明 Alice \text{Alice} Alice 的话是错误的。

输入格式

第一行包含一个正整数 T T T,表示有 T T T 组测试数据。

每组测试数据的第一行包含三个整数 n , k , h n,k,h n,k,h,表示有 n n n 个人偶,蹦极台有 k k k 个高度,分别为 h , 2 × h , ⋯   , k × h h,2\times h,\cdots,k\times h h,2×h,,k×h

接下来的一行中有 n n n 个整数,代表 w i w_i wi,即每个人偶的强度。

接下来的一行中有 n n n 个整数,代表 v i v_i vi,即每个人偶的飞行速度。

输出格式

对于每组测试数据,输出 k k k 个人偶的编号,表示使这 k k k 个人偶在 h , 2 × h , ⋯   , k × h h,2\times h,\cdots,k\times h h,2×h,,k×h 上表演可以使所需的准备时间最短。如果有多种方案,你可以输出任意一种。

输入输出样例

输入 #1

5 3 2
1 2 3 2 1
1 2 1 2 10

输出 #1

5 2 4

说明/提示

样例解释

编号为 5 5 5 的人偶站在高度 2 2 2,她飞到目标需要 2 / 10 = 0.2 2/10=0.2 2/10=0.2 秒。

编号为 2 2 2 的人偶站在高度 4 4 4,她飞到需要 4 / 2 = 2 4/2=2 4/2=2 秒。

编号为 3 3 3 的人偶站在高度 6 6 6,她飞到目标需要 6 / 2 = 3 6/2=3 6/2=3 秒。

因此,最短的准备时间为 3 3 3 秒,可以证明,没有其他方案所需的时间比这种更短。

数据范围与约定

对于 20 % 20\% 20% 的数据,保证 n ≤ 300 n\leq 300 n300

对于 40 % 40\% 40% 的数据,保证 n ≤ 5000 n\leq 5000 n5000

对于 100 % 100\% 100% 的数据,保证 n ≤ 100000 , T ≤ 10 n\leq 100000,T\leq 10 n100000,T10

解题思路

二分答案。

先按强度为第一关键字,飞行速度第二关键字从小到大排序,二分最少的时间 t i m e time time,从第 1 1 1个人偶到第 n n n个人偶,假设当前是要选定第 j j j个人偶,则只要满足 j × h / v i ≤ t i m e j\times h/v_i\leq time j×h/vitime,也就是 j × h ≤ v i × t i m e j\times h\leq v_i\times time j×hvi×time。之后判定最大能选的人偶是否 ≥ k \geq k k

代码实现

#include <stdio.h>
#include <string.h>
#include <cmath>
#include <algorithm>
using namespace std;

struct LEM
{
    int m;
    int v;
    int id;
    bool operator<(const LEM& b) const { return m==b.m?v < b.v:m<b.m; }
};
LEM lemm[100010];
bool dblcmp(double a,double b)
{
	return fabs(a-b)<1e-9 || a<=b;
}
bool verify(int n,int k,int h,double T)
{
    int pickout = 0;
    for(int i = 0;i < n;i++)
    {
        if(dblcmp(((double)(h*(pickout+1))),(double)lemm[i].v*T))
        {
            pickout++;
            if(pickout >= k) break;
        }
    }
    return pickout >= k;
}

int main(void)
{
	int TK = 0;
	scanf("%d",&TK);
	while(TK--)
	{
		int n = 0;
		int k = 0;
		int h = 0;
		scanf("%d %d %d",&n,&k,&h);
		for(int i = 0;i < n;i++) scanf("%d",&lemm[i].m);
		for(int i = 0;i < n;i++) scanf("%d",&lemm[i].v);
		for(int i = 0;i < n;i++) lemm[i].id = i+1;
		sort(lemm,lemm+n);
		double l = 0;
		double r = 10000000000;
		while((r-l)/r>1e-9)
		{
			double mid = (l+r)/2.0;
			if(verify(n,k,h,mid)) r = mid;
			else l = mid;
		}
		int pickout = 0;
		for(int i = 0;i < n;i++)
		{
			if(dblcmp((double)((pickout+1)*h),(double)lemm[i].v*r))
			{
				printf("%d ",lemm[i].id);
				pickout++;
				if(pickout >= k) break;
			}
		}
		putchar('\n');
	}
    return 0;
}
  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值