2021-1-22 二分

C ——Aggressive cows

Farmer John has built a new long barn, with N (2 <= N <= 100,000) stalls. The stalls are located along a straight line at positions x1,…,xN (0 <= xi <= 1,000,000,000).

His C (2 <= C <= N) cows don’t like this barn layout and become aggressive towards each other once put into a stall. To prevent the cows from hurting each other, FJ want to assign the cows to the stalls, such that the minimum distance between any two of them is as large as possible. What is the largest minimum distance?

Input

  • Line 1: Two space-separated integers: N and C

  • Lines 2…N+1: Line i+1 contains an integer stall location, xi

Output

  • Line 1: One integer: the largest minimum distance

Sample Input

5 3
1
2
8
4
9

Sample Output

3

Hint

OUTPUT DETAILS:

FJ can put his 3 cows in the stalls at positions 1, 4 and 8, resulting in a minimum distance of 3.

Huge input data,scanf is recommended.

大致题意:
有c头牛要放进n个位置,其中每个位置的距离从第n行输入。输出两头奶牛的大小距离的最大值。
简而言之,相当于一个存在n个点的线段上要找到c个位置,求出任意两个位置最小距离的最大值。

方法:

扫描二维码关注公众号,回复: 14650670 查看本文章
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<math.h>
#include<stdio.h>
#include<math.h>
#include<string.h>
using namespace std;
int a[10000+10];
int n,c;
//二分+贪心
//二分枚举相邻牛的距离,判断大于等于该间距能否放进c头牛 

int main(){
    
    
	scanf("%d %d",&n,&c);
	for(int i=0;i<n;i++)
	    scanf("%d",&a[i]);
	sort(a,a+n);
	int l=1,r=a[n-1]-a[0],m;//r一定等于大于最大距离 
	while(l<=r){
    
    
		m=(l+r)/2;//接下去判断 间距为m能否成立 
		int cnt=1,j=0;//cnt等于1是因为已经有第一头牛放在a[0]的位置 
		//j代表上一头奶牛的位置 
		for(int i=1;i<n;i++){
    
    //枚举剩下位置 
			if(a[i]-a[j]>=m){
    
    cnt++;j=i;}
		}
		if(cnt>=c)l=m+1;//当间距为m时能放进等于或大于c头奶牛,最小间距还能再扩大 
		else r=m-1;
	}
	cout<<r<<endl;
}

F—— 4 Values whose Sum is 0The SUM

problem can be formulated as follows: given four lists A, B, C, D of integer values, compute how many quadruplet (a, b, c, d ) ∈ A x B x C x D are such that a + b + c + d = 0 . In the following, we assume that all lists have the same size n .

Input

The first line of the input file contains the size of the lists n (this value can be as large as 4000). We then have n lines containing four integer values (with absolute value as large as 228 ) that belong respectively to A, B, C and D .

Output

For each input file, your program has to write the number quadruplets whose sum is zero.

Sample Input

6
-45 22 42 -16
-41 -27 56 30
-36 53 -37 77
-36 30 -75 -46
26 -38 -10 62
-32 -54 -6 45

Sample Output

5

Hint

Sample Explanation: Indeed, the sum of the five following quadruplets is zero: (-45, -27, 42, 30), (26, 30, -10, -46), (-32, 22, 56, -46),(-32, 30, -75, 77), (-32, -54, 56, 30).

大致题意:
首先给出n,以及一个n行4列的矩阵,要求求出从每列任意取一个数且四个数之和为0的情况数。

代码:

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
int a[4002][4],sum[16000002];//16000002的来源是最多会有4000x4000个数。
int main()
{
    
    
    int n;
    while(~scanf("%d",&n)){
    
    
        for(int i=0;i<n;i++)
            scanf("%d %d %d %d",&a[i][0],&a[i][1], &a[i][2],&a[i][3]);
        int k=0;
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++){
    
    
                sum[k++]=a[i][0]+a[j][1];//直接枚举会超时 
                //所以先将1、2两列相加,并将和存入sum数组
                //sum+a[i][2]+a[j][3]=0 -> sum=-(a[i][2]+a[j][3])
                //再将sum数组的值和-(a[i][2]+a[j][3])进行比较
                //两者值相等则代表四个数和为0
            }
            
            
        sort(sum,sum+k);//排序,需要加头文件#include<algorithm>
        int cnt=0;
        for(int i=0;i<n;i++)
           for(int j=0;j<n;j++){
    
    
           	   cnt+=upper_bound(sum,sum+k,-a[i][2]-a[j][3])-lower_bound(sum,sum+k,-a[i][2]-a[j][3]);
           	   //upper_bound(start,end,n)返回第一个大于n的地址
			   //lower_bound(start,end,n)返回第一个大于等于n的地址
			   //两者相减得出start到end中等于n的数量 
		   }
	    cout<<cnt<<endl;
}
}

Notice

(1)upper_bound(start,end,n)返回第一个大于n的地址
lower_bound(start,end,n)返回第一个大于等于n的地址
两者相减得出start到end中等于n的数量

(2)sort(a,a+n,t)即将数组a的a[0]-a[n-1]进行排序,排列顺序为t。若不存在t,则默认按升序排序。

G —— Defuse the Bombs

The terrorists have planted some bombs in a building! Our hero, Little Horse, decides to rescue the people in the building. Unfortunately, there is more than one bomb, and Little Horse is unable to defuse all of them. To strive for more time for other people to escape, Little Horse decides to sacrifice himself.

There are n bombs in the building, each of which has a countdown clock. In the beginning, the i-th bomb’s clock is set to ai. Then:

  1. Little Horse chooses one bomb, making its clock increase by 1.
  2. Every bomb’s clock decreases by 1.
  3. If at least one clock becomes lower than 0, all the bombs will explode. Otherwise, go back to step 1.

Obviously, the explosion is not avoidable. What a sad story. But Little Horse doesn’t care about his survival now. He just wants to strive for more time. So can you tell him how many times he can do step 1 at most before the explosion?

Input

The first line of the input contains an integer T (1≤T≤100) — the number of test cases.

The first line of the input contains an integer n (2≤n≤105) — the number of bombs. The sum of n will not exceed 3×105.

The next line contains n numbers a1,a2,…,an (0≤a1,a2,…,an≤109) — the clocks of the bombs in the beginning.

Output

For the x-th test case, if the answer is y, output Case #x: y in a single line.

Sample Input

2
2
1 1
3
1 2 3

Sample Output

Case #1: 3
Case #2: 4

大致题意:
首行输入T,代表有T组测试数据。对于每组测试数据,首行输入炸弹数量n,第二行输入n个整数,代表该炸弹的时间。此时对所有炸弹有同时进行的两个操作:(1)将某一个炸弹的时间+1(2)将所有炸弹的时间-1。每轮操作完成,都将判断所有炸弹时间状态,如果一个及以上的炸弹时间小于0,则所有炸弹同时爆炸;否则进入下一轮操作。现在要输出最多能进行几轮操作

方法:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<math.h>
#include<stdio.h>
using namespace std;
#define MAXN 1e5+10
long long a[100005];
	int T,n;
	
	
int check(long long x){
    
    
	long long sum=0;
	for(int i=0;i<n;i++){
    
    //后续用(x-1)的目的:
//只要确保(x-1)轮操作进行完不爆炸,则进入第x轮操作

		if(a[i]<x-1)//剩余时间数小于轮数,即在(x-1)轮前会小于0
		//因此要使能进行(x-1)轮操作,必须对其进行+1操作
		   sum+=(x-1)-a[i];//差值即为需要进行的+1操作轮数
		   //sum用于储存要进行(x-1)轮操作,所需的+1操作数
		if(sum>x-1)//(x-1)轮操作所能提供的+1操作数是(x-1)
		//若sum<(x-1),则代表在第(x-1)轮前,已有炸弹的时间数减为0
		   return 0;
	}
	return 1;
}


int main(){
    
    
    int i=1;
    scanf("%d",&T);
		while(T--){
    
    
			scanf("%d",&n);
			for(int i=0;i<n;i++)
			   scanf("%lld",&a[i]);
			long long l=0,r=1e14,m;//r是猜测的最大时间,解释如下
			//假设无论给定的炸弹时间数多大或者给定的炸弹数目多少
			//都存在x使能进行的操作轮数<=x
			//那么就能得到为某一炸弹情况时,最多操作轮数x1属于(0,x]
			//因此要查找x1的具体大小,可以在范围(0,x]内进行二分查找
			while(l<=r){
    
    
				m=(r+l)/2;
				if(check(m))l=m+1;
				else r=m-1;
			}
			printf("Case #%d: %lld\n",i,l-1);
			i++;
		}
	
}

二分模板

// 判断条件很复杂时用check函数,否则if后直接写条件即可
bool check(int mid) {
    
    
    ...
    return ...;
}
 
// 能二分的题一定是满足某种性质
// if的判断条件是让mid落在满足你想要结果的区间内

// 找满足某个条件的第一个数  
int bsearch_1(int l, int r)
{
    
    
    while (l < r)
    {
    
    
        int mid = l + r >> 1;
        if (check(mid)) r = mid;  
        else l = mid + 1;
    }
    return l;
}

// 找满足某个条件的最后一个数  
int bsearch_2(int l, int r)
{
    
    
    while (l < r)
    {
    
    
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

猜你喜欢

转载自blog.csdn.net/m0_52433146/article/details/112986292