清北学堂第一题 游乐园 SmartOJ 1815(二分查找的精髓)
来源:互联网 发布:前列腺高潮经验知乎 编辑:程序博客网 时间:2024/04/28 05:11
题目描述
游乐园里新推出一个游戏——飞机驾驶体验。有N-1个小朋友来玩这个游戏,他们排成长长的一列。这个游戏一共有M架“飞机”可供驾驶,每架飞机的使用时间都是有限制的,第i架“飞机”的使用时间是si分钟。
一开始所有“飞机”都是闲置着的,然后排队等候着的小朋友依次上“飞机”。如果有飞机闲置,则小朋友一定会上去玩(小朋友不会在意飞机使用的时间);如果同时有多架“飞机”闲置着,小朋友一定会选择标号最小的那架。
现在你带着你的弟弟来到了游乐园,排到了最后一个位置。你想知道你弟弟会在哪架“飞机”上体验。
输入格式
第一行两个数N和M。
接下来一行M个数,第i个表示si。
输出格式
输出一个数,表示你弟弟会坐上哪架飞机。
样例输入
22 5
1 2 3 4 5
样例输出
4
数据范围与提示
数据规模对于30%的数据 N≤1 000 000;对于100%的数据 1≤N≤1 000 000 000,1≤M≤1 000。
数据范围如此之庞大,循环暴力解决是绝对不行的!!!!!!!!就连单层循环都不允许~~~~~为此我哭了一阵!!!
程序代码解析
解析:
(1)如果完成一件事一次需要b分钟,那么如果总共用n分钟,那么共完成了几次,第n分钟正在做第几次(不一定完成)。
技巧:①共完成了n/b次。
②n分钟正在做第(n+b-1)/b次。
②证明:假设n/b=k,n%b=y;
那么,可知如果y==0,那么总共就做了k次,且第k次恰好完成;如果y!=0,那么总共做了k+1次,但是第k+1次正在做,还没有完成。
为了避免余数的讨论,进行这样的处理(n+b-1)/b。
而:(n+b)/b与n/b是等效的,只是商k+1而已。
如果原先n恰好足够b,那么n-1一定不足b,(n-1)%b=y-1。
故在原来的基础上加上一个b-1之后,与原来等价。不足b时结果加1.
(2)二分法的精髓:二分并不一定局限于对有序数列的查找,对于无需数列,可以转换角度建立二分模型,将不能二分的情况转化为二分的模型,如本题中用下标与总时间建立模型进行二分。当然这建立在(1)可求的基础上。
以下代码摘自:http://blog.163.com/sentimental_man/blog/static/730016182011931103428207/
#include <iostream>
#include <stdio.h>
using namespace std;
typedef long long I64;
const int MAXN = 1001;
const int INF = 0x7fffffff;
int g_n, g_m, g_time[MAXN], g_min;
//输入并找出最小值
void Input()
{
scanf("%d%d", &g_n,&g_m);
int i;
g_min = INF;
for (i = 0; i < g_m; i++)
{
scanf("%d",&g_time[i]);
if (g_time[i] < g_min) g_min =g_time[i];
}
}
I64 GetNumber(I64 minite) //统计minite分钟内能容纳小朋友的总人数
{
int i;
I64 number = 0;
for (i = 0; i < g_m &&number < g_n; i++)
number += (minite + g_time[i] -1) / g_time[i]; //用的就是技巧(1)
return number;
}
I64 FindTime() //找到n这个人玩飞机的时间
{
I64 l, r, mid, num;
l = 0, r = ((I64) g_min) * g_n; //开始的时候这边忘记类型转化,导致数据溢出,第五组数据一直过不了!在整数和长整数混用时一定要注意!
while (l < r)
{
mid = (l + r) / 2;
num = GetNumber(mid);
if (num >= g_n)
r = mid;
else
l = mid + 1;
}
return r;
}
int FindId(I64 minite) //寻找所玩飞机的编号
{
int i;
I64 t_n = g_n;
t_n -= GetNumber(minite - 1); //得出最后一分钟内有多少个小朋友正在玩飞机
minite--;
for (i = 0; i < g_m; i++)
{
if (minite % g_time[i] == 0) //如果求余为0,那么一定会有小朋友上飞机
{
t_n--;
if (t_n == 0) return i + 1;
}
}
return -1;
}
int main()
{
Input();
I64 time = FindTime(); //先二分找出n这个人玩飞机的时间
int id = FindId(time); //根据这个时间找出n小朋友玩的飞机
printf("%d\n", id);
// system("pause");
return 0;
}
时间复杂度基本能达到O(log(2,n));
我带着Orz的心情笑了!!!!!!!!!!!~~~
- 清北学堂第一题 游乐园 SmartOJ 1815(二分查找的精髓)
- [Tyvj1655] 游乐园 二分查找
- 立方数(清北学堂济南刷题冲刺)
- 【清北学堂】 死亡(death)
- 清北学堂游记(1)
- 清北学堂游记(2)
- 清北学堂总结(未完待续。。。。。。。)
- 【清北学堂】number
- 【清北学堂】dwarf
- 清北学堂上课记录
- 清北学堂夏令营有感
- 清北学堂复习笔记
- 清北学堂集训day1
- 【坑爹】2016.11.8 清北学堂钟长者的P73
- 二分查找----(返回第一个找到的值)
- ☆游乐园 二分+模拟
- 清北学堂十一培训酱油记
- 2016国庆清北学堂游记
- datagridview绑定数据用法
- ZOJ Problem Set - 1456
- 计算机网络学习笔记(一)
- 八皇后问题
- HDU3790(Dijkstra)
- 清北学堂第一题 游乐园 SmartOJ 1815(二分查找的精髓)
- select 函数使用方法
- shell 脚本多进程创建 mysql 测试数据
- Nodejs+Extjs+Mongodb开发第三天 登录页面(1)
- Java-IO流
- 集群理解
- robotium跨应用处理办法
- 百度之星第四题(记忆化搜索)
- Android(安卓)系列手机怎么通过电脑安装手机应用程序?