nyoj 229 工程
-
描述
- 有n个工人做两个工程A和B,每个工程都被分为相同的m份,给你第i个工人做A中的一份需要的时间Xi秒,和做B中的一份所需时间Yi秒,问最短需要多少时间可以完成这两项工程。
-
输入
- 第一行是一个整数t (1 <= t <= 100),表示有t组测试数据;
每组测试数据第一行有两个整数 n (1 <= n <= 100), m (1 <= m <= 100).
接下来的n行,每行有两个整数Xi,Yi;
输出 - 输出最短时间,占一行。 样例输入
-
1 3 20 1 1 2 4 1 6
样例输出 -
18
- 第一行是一个整数t (1 <= t <= 100),表示有t组测试数据;
二分模型。最关键的是全局的思想。
此题的模型 。
1、 求最短时间。
2、单调性。 给的时间越长,越易完成。
这个函数模型为。 f(x) = 0 (x < T)
f(x) = 1 (x >= T)
这个分段函数为单调函数(非严格递增)。
3、 judge 函数也就是2中的f(x)的编写 。 背包。
const int Max_N = 108 ;
int dp[Max_N] ;
int A[Max_N] , B[Max_N] ;
int N , M ;
int DP(int Time){ //在时间为Time的情况下能否搞定
int man , i , j , k ;
memset(dp , -1 , sizeof(dp)) ;
for(i = 0 ; i <= M && i*A[1] <= Time ; i++) //第一个人做i个A,还可以做dp[i]个B
dp[i] = (Time-i*A[1])/B[1] ;
if(dp[M] >= M)
return 1 ;
for(man = 2 ; man <= N ; man++){
for(i = M ; i >= 0 ; i--){ //从大到小更新,联想尺子
for(j = 0 ; j<=i && j*A[man] <= Time ;j++){ //从小到大,是为了满足i从大到小。
if(dp[i-j] != -1)
dp[i] = max(dp[i] , dp[i-j] + (Time-j*A[man])/B[man]) ;
}
}
}
return dp[M] >= M ;
}
int Ans(int up){ //二分枚举
int Left = 1 ;
int Right = up ;
int Mid , ans ;
while(Left <= Right){
Mid = (Left + Right) >> 1 ;
if(DP(Mid)){
ans = Mid ;
Right = Mid - 1 ;
}
else
Left = Mid + 1 ;
}
return ans ;
}
int main(){
int i , t , _up ;
scanf("%d" ,&t) ;
while(t--){
scanf("%d%d" ,&N ,&M) ;
_up = 0 ;
for(i = 1 ; i <= N ; i++){
scanf("%d%d" ,&A[i] , &B[i]) ;
_up = max(_up , A[i]) ;
_up = max(_up , B[i]) ;
}
printf("%d\n" , Ans(_up*M*2)) ;
}
return 0 ;
}
nyoj 804 Gift
http://acm.nyist.net/JudgeOnline/problem.php?pid=804
题意 : N种珠子, 每种x[i] 个 。 要组成长M的项链,使得每条项链珠子都不用 。 求最多能组成多少条这样的项链。
1、 求最大值。
2 、单调性。记 f(x) = 1 可以组成x个 。
f(x) = 0 不能组成x个。
对任意的x < y ,有 f(x) >= f(y)
3、judge(x)函数 。
组成x条项链, 对于每一种珠子, 最多出现x个 (也就是没条项链都参与)。
一共可以参与的珠子个数从上到下, 从做到右平均分配到x条项链中,判断长度是否>=M。
const int Max_N = 1008 ;
int N , M ;
int x[Max_N] ;
int judge(int k){
int sum = 0 ;
for(int i = 1 ; i <= N ; i++)
sum += x[i] >= k ? k : x[i] ;
return sum/M >= k ;
}
int Ans(int up){
int Left = 0 ;
int Right = up ;
int Mid , ans ;
while(Left <= Right){
Mid = (Left + Right) >> 1 ;
if(judge(Mid)){
ans = Mid ;
Left = Mid + 1 ;
}
else
Right = Mid - 1 ;
}
return ans ;
}
int main(){
int i , sum ;
while(scanf("%d" ,&N) && N){
sum = 0 ;
for(i = 1 ; i <= N ; i++){
scanf("%d" ,&x[i]) ;
sum += x[i] ;
}
scanf("%d" ,&M) ;
printf("%d\n" , Ans(sum/M)) ;
}
return 0 ;
}
nyoj 586 疯牛
-
描述
- 农夫 John 建造了一座很长的畜栏,它包括N (2 <= N <= 100,000)个隔间,这些小隔间依次编号为x1,...,xN (0 <= xi <= 1,000,000,000).
但是,John的C (2 <= C <= N)头牛们并不喜欢这种布局,而且几头牛放在一个隔间里,他们就要发生争斗。为了不让牛互相伤害。John决定自己给牛分配隔间,使任意两头牛之间的最小距离尽可能的大,那么,这个最大的最小距离是什么呢?-
输入
- 有多组测试数据,以EOF结束。
第一行:空格分隔的两个整数N和C
第二行——第N+1行:分别指出了xi的位置
输出 - 每组测试数据输出一个整数,满足题意的最大的最小值,注意换行。 样例输入
-
5 3 1 2 8 4 9
样例输出 -
3
- 有多组测试数据,以EOF结束。
本题是很经典的 青蛙过河 模型。
const int Max_N = 100008 ;
int N , M ;
int x[Max_N] ;
int judge(int Len){
int dot = 1 , now = x[1] , i ;
for(i = 2 ; i <= N ; i++){
if(x[i] - now < Len)
continue ;
else{
now = x[i] ;
dot++ ;
if(dot >= M)
return 1 ;
}
}
return dot >= M ;
}
int Ans(int up){
int Left = 0 ;
int Right = up ;
int Mid , ans ;
while(Left <= Right){
Mid = (Left + Right) >> 1 ;
if(judge(Mid)){
ans = Mid ;
Left = Mid + 1 ;
}
else
Right = Mid - 1 ;
}
return ans ;
}
int main(){
int i , sum ;
while(scanf("%d%d" ,&N ,&M) != EOF){
for(i = 1 ; i <= N ; i++)
x[i] = getint() ;
sort(x+1 , x+1+N) ;
printf("%d\n" , Ans(x[N] - x[1])) ;
}
return 0 ;
}
关于double二分,奔跑的xiaodao |
某天,DS同学和他的妹子终于要见面了。DS在遥远的西藏,妹子在北京,中间隔着一条长长的川藏公路。DS和妹子都在这条公路上相向而行,因为过于思念对方,DS派出了xiaodao作为自己的情书信使。 DS和妹子相向而行,速度为 v1 , v2 m/s。 尽职尽责的xiaodao同学以 v m/s 的速度奔跑,他一开始拿着DS的信向妹子的方向狂奔,遇到妹子之后毫不停歇,拿着妹子的书信继续以 v 的速度向DS奔跑,周而复始,一直到DS和妹子相遇为止。好辛劳的xiaodao。 但是DS是个胖子,妹子是女生,大家都体力不太行。已知DS奔跑 T1 s 之后就要休息 Wait1 s ,妹子奔跑 T2 s 之后就要休息 Wait2 s 。而xiaodao是不会休息的!经过计算,DS和妹子的初始距离为 L 。 xiaodao想问你,当DS和妹子终于相遇的时候,xiaodao这时候已经奔跑了多少 m 的距离。 |
Input |
第一行一个整数 T , 代表数据组数,以下 T 组数据。 每组数据包含 8 个实数 分别代表 v1 , v2 , v , T1 , T2 , Wait1 , Wait2 , L。 1 <= v1 , v2 <= 100 , v1 < v <= 100 , 1 <= T1 , T2 <= 1000 , 0 <= Wait1 , Wait2 <= 1000 . 1 <= L <= 10000 . |
Output |
对于每组数据输出一个实数 S 代表 xiaodao 奔跑的距离。 |
Sample Input |
1 1.00 1.00 2.00 1.00 1.00 0.00 0.00 2.00 |
Sample Output |
2.000000000 |
Source |
哈尔滨理工大学第四届ACM程序设计竞赛(同步赛) |
typedef long long LL ;
typedef double LD ;
#define eps 1e-8
LD t1 ,wait1 , t2 ,wait2 , v1 , v2;
LD Lenth ;
int judge(LD Time){
LD T , len1 , len2 , t ;
LL tt1 = floor(Time/(t1+wait1)) ;
len1 = v1*tt1*t1 ;
if(Time - tt1*(t1+wait1) >= t1)
t = t1 ;
else
t = Time - tt1*(t1+wait1) ;
len1 += v1*t ;
LL tt2 = floor(Time/(t2+wait2)) ;
len2 = v2*tt2*t2 ;
if(Time - tt2*(t2+wait2) >= t2)
t = t2 ;
else
t = Time - tt2*(t2+wait2) ;
len2 += v2*t ;
if(len1 + len2 > Lenth || fabs(len1 + len2 - Lenth) < eps)
return 1 ;
return 0 ;
}
LD b_s(){
LD L , R , Mid , ans ;
L = 0.0 ;
R = 1e8 ;
while(L + eps < R){
Mid = (L + R) * 0.5 ;
if(judge(Mid)){
ans = Mid ;
R = Mid ;
}
else
L = Mid ;
}
return ans ;
}
LD v ;
int main(){
int t ;
cin>>t ;
while(t--){
scanf("%lf%lf%lf%lf%lf%lf%lf%lf" , &v1 ,&v2 ,&v ,&t1,&t2,&wait1,&wait2,&Lenth) ;
printf("%.9lf\n",b_s() *v) ;
}
return 0 ;
}
给出农夫在n天中每天的花费,要求把这n天分作m组,每组的天数必然是连续的,要求分得各组的花费之和应该尽可能地小,最后输出各组花费之和中的最大值
const int maxn = 100008 ;
int x[maxn] , m , n ;
int judge(int c){
int s = 1 , t = 0 ;
int i = 1 ;
while(i <= n){
if(t + x[i] > c){
s++ ;
t = x[i] ;
}
else t += x[i] ;
i++ ;
}
return s <= m ;
}
int main(){
int i , L , R , M , s ;
while(cin>>n>>m){
R = L = 0 ;
for(i = 1 ; i <= n ; i++){
scanf("%d" ,&x[i]) ;
R += x[i] ;
L = max(L , x[i]) ;
}
while(L <= R){
M = (L + R) >> 1 ;
if(judge(M)){
s = M ;
R = M - 1 ;
}
else L = M + 1 ;
}
printf("%d\n" , s) ;
}
return 0 ;
}