CodeForces 373C Counting Kangaroos is Fun(袋鼠藏口袋,二分)

C. Counting Kangaroos is Fun
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

There are n kangaroos with pockets. Each kangaroo has a size (integer number). A kangaroo can go into another kangaroo's pocket if and only if the size of kangaroo who hold the kangaroo is at least twice as large as the size of kangaroo who is held.

Each kangaroo can hold at most one kangaroo, and the kangaroo who is held by another kangaroo cannot hold any kangaroos.

The kangaroo who is held by another kangaroo cannot be visible from outside. Please, find a plan of holding kangaroos with the minimal number of kangaroos who is visible.

Input

The first line contains a single integer — n (1 ≤ n ≤ 5·105). Each of the next n lines contains an integer si — the size of the i-th kangaroo(1 ≤ si ≤ 105).

Output

Output a single integer — the optimal number of visible kangaroos.

Examples
input
8
2
5
7
6
9
8
4
2
output
5
input
8
9
1
6
2
6
5
8
3
output
5


题意:

有 n 个袋鼠的口袋,袋鼠 A 的口袋 >= 袋鼠 B 口袋的 2 倍,后者就能够藏在前者口袋中。

问最后最多能剩下多少个能够看到的袋鼠


思路:

跟之前做的一串数字组合类似。。。

二分查找方法


代码:

#include<cstdio>
#include<algorithm>
#define MYDD 11030

using namespace std;

int num[50*MYDD];
bool cmp(int x,int y) {
	return x>y;
}

int main() {
	int n;
	scanf("%d",&n);
	for(int j=0; j<n; j++)
		scanf("%d",&num[j]);

	sort(num,num+n,cmp);

	int left=n/2,del=0;	
	//int v=1;
	for(int j=0; j<n; j++) {
		if(num[j]==0)
			continue;
		while(left<n) {//折半查找满足条件的值 
			if(num[left]!=0&&(2*num[left]<=num[j])) {
				num[j]=num[left]=0;//找到一组这个袋鼠能够待在另一个袋鼠口袋中 
				del++;
				left++;
				break;
			} else
				left++;
			//printf("*************%d**\n",v++);
		}

	}
	printf("%d\n",n-del);//剩余可见的袋鼠 
	return 0;
}



RYC学长的代码:

#include<iostream>  
#include<cstdio>  
#include<cstdlib>  
#include<cstring>  
#include<algorithm>  
#include<cmath>  
#include<queue>  
#include<stack>  
#include<list>  
#include<functional>  
using namespace std;  
const int maxn=1000010;  
int num[maxn],temp[maxn],n;  
bool judge(int mid){  
    if(mid<(n+1)/2)return false;  
    for(int i=mid+1;i<=n;++i){  
        if(num[i]*2>num[i-mid])return false;  
    }  
    return true;  
}  
bool cmp(int a,int b){  
    return a>b;  
}  
int main()  
{  
    scanf("%d",&n);  
    for(int i=1;i<=n;++i){  
        scanf("%d",&num[i]);  
    }  
    sort(num+1,num+n+1,cmp);  
    int left=1,right=n,ans;  
    while(left<=right){  
        int mid=(left+right)/2;  
        if(judge(mid)){  
            ans=mid;  
            right=mid-1;  
        }  
        else {  
            left=mid+1;  
        }  
    }  
    printf("%d\n",ans);  
    return 0;  
}  


Codeforces Round 1000 Div. 2 F1 题目 "Counting Is Not Fun (Easy Version)" 中,问题的核心是计算满足特定条件的子数组数量,而这些子数组的元素值与它们在子数组中的位置相关。 ### 题目简述 题目要求找到数组中满足特定条件的子数组数量。具体而言,对于一个长度为 $ n $ 的数组 $ a $,要求统计所有子数组 $ [l, r] $(其中 $ 1 \leq l \leq r \leq n $)的数量,使得对于该子数组内的每个位置 $ i $(相对于子数组的起始点 $ l $ 的偏移),满足 $ a[i] = i - l $。 ### 解题思路 1. **滑动窗口方法**:可以使用滑动窗口的思想来解决这个问题。我们遍历数组,尝试找到尽可能长的连续段,其中每个元素的值等于其相对于当前段起始位置的偏移量。对于每一个起始位置 $ l $,找到最大的 $ r $,使得所有 $ a[i] = i - l $ 对于 $ i \in [l, r] $ 成立。 2. **统计符合条件的子数组数量**:对于每一个满足条件的连续段,长度为 $ len $,则该段内可以形成的子数组数目为 $ len \times (len + 1) / 2 $。这是因为长度为 $ len $ 的连续段可以形成 $ len + (len - 1) + ... + 1 = len \times (len + 1) / 2 $ 个子数组。 3. **遍历数组**:通过遍历数组并维护当前段的起始位置,可以高效地找到所有符合条件的连续段并统计其对应的子数组数量。 ### 时间复杂度 该算法的时间复杂度为 $ O(n) $,因为每个元素最多被访问一次,且没有嵌套循环。 ### 示例代码 以下是一个实现该思路的 Python 示例代码: ```python n = int(input()) a = list(map(int, input().split())) count = 0 i = 0 while i < n: if a[i] != 0: i += 1 continue # 找到最长的连续段 j = i while j < n and a[j] == j - i: j += 1 length = j - i count += length * (length + 1) // 2 i = j print(count) ``` ### 代码说明 1. 首先读取输入的数组。 2. 遍历数组,寻找所有起始位置 $ i $,其中 $ a[i] = 0 $,因为这是可能的子数组起点。 3. 对于每一个起点 $ i $,找到最长的连续段 $ [i, j) $,使得所有元素满足 $ a[k] = k - i $。 4. 根据连续段的长度计算符合条件的子数组数量,并累加到最终结果中。 ### 相关优化 在实现中,需要注意避免重复计算或遗漏某些情况,例如当数组中存在多个连续段时,确保每个段都被正确分割并计算。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值