Codeforces Round #219 (Div. 1) A. Counting Kangaroos is Fun

2 篇文章 0 订阅
2 篇文章 0 订阅

A. 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.


题目大意:有n个袋鼠,每个袋鼠的大小为Si,袋鼠i可以装进袋鼠j的袋子里面的条件是,2 * Si <= Sj ,一只袋鼠不能装多只袋鼠,装了一只袋鼠的袋鼠不能装入它袋鼠。装进袋子里的袋鼠会被看不见,问最大的可见的袋鼠的数量。n <= 5 * 10 ^ 5 , Si <= 10 ^ 5


错误的想法:一上来,就有一些贪心的念头,比如大的装能装下的最小小的,大的装能装下的最大的,还可以从小的方向考虑,然后又发现大的能装的袋鼠包含小一些的能装的的袋鼠,然后又想出一些贪心的策略,这些东西浪费了半个小时,悲剧的举反例,一一验证失败。

然后想到了匹配,二分图的匹配,以前有人说那样的图不是二分图,但我刚才证明了,就连接从大到小的二分图的结果和正确结果相同,不必用带花树之类神奇的东西。但实际上复杂度O(VE),简直玩叼。

然后,又想出来了一种错误的按照2^n划分,然后一点一点贪心消耗。当然也是错的,代码没拍完就结束了。

然后,看了一下tourist 的代码 3分钟出解,尼玛,我什么也不想说了,怎么玩,还是做div2去吧,渣渣。


正确的想法:主要是假想问题已经结出来了。已经有了不同袋鼠之间的一个最佳配对。依照最开始的一个观察:对于袋鼠i,所有小于等于Si / 2 的袋鼠都可以被装进袋中。考虑边界,特殊情况,最大的袋鼠,最小的袋鼠。为什么没有被选上,显然是可以被选上的。从新审视情况,选特殊的,次小的呢,次大的呢?那么小的袋鼠可以尽量的小,大的袋鼠可以尽量的大。那么选择的袋鼠占据最大的以及最小的一端。如果匹配有交叉,小的反而可以装大的,那么也可以装小的,大的比小的大,自然也可以装小的能装下的袋鼠。


算法1:二分能装入袋中的袋鼠数量,由于没有交叉,可以从小到大依次验证。

算法2:两个指针,一个指向还没有装袋鼠的大袋鼠,另一个指向尝试装入袋中的袋鼠,如果可以装入,同时减少,否则,小的指针减少,大的不动,相当于小的已经匹配的袋鼠,整体向更小的方向移动。

代码1:

# include <iostream>
# include <cstdio>
# include <algorithm>
# include <cmath>
# include <cstring>
# include <cstdlib>
# include <cassert>

using namespace std ;

typedef long long LL ;

int s [ ( int ) 1e6 ] ;

int main () {

# ifdef DEBUG
	FILE * fPtr = freopen ( "a.in" , "r" , stdin ) ;
	assert ( fPtr != NULL ) ;
	fPtr = freopen ( "a.out" , "w" , stdout ) ;
	assert ( fPtr != NULL ) ;
# endif

	int n ; 

	while ( cin >> n ) {

		for ( int i = 0 ; i < n ; i ++ ) {

			cin >> s [ i ] ;
		}

		sort ( s , s + n ) ;

		int low = 0 , high = n / 2 ;

		while ( low <= high ) {

			int mid = ( low + high ) / 2 ;

			int ok = 1 ;

			for ( int i = 0 ; i < mid ; i ++ ) {

				if ( 2 * s [ i ] > s [ n - mid + i ] ) {

					ok = 0 ;
					break ;
				}
			}

			if ( ok ) {

				low = mid + 1 ;
			}
			else {

				high = mid - 1 ;
			}
		}

		cout << n - high << endl ;
	}

	return 0 ;
}


代码2:

# include <iostream>
# include <cstdio>
# include <algorithm>
# include <cmath>
# include <cstring>
# include <cstdlib>
# include <cassert>

using namespace std ;

typedef long long LL ;

int s [ ( int ) 1e6 ] ;

int main () {

# ifdef DEBUG
	FILE * fPtr = freopen ( "a.in" , "r" , stdin ) ;
	assert ( fPtr != NULL ) ;
	fPtr = freopen ( "a.out" , "w" , stdout ) ;
	assert ( fPtr != NULL ) ;
# endif

	int n ;

	while ( cin >> n ) {

		for ( int i = 0 ; i < n ; i ++ ) {

			cin >> s [ i ] ;
		}

		sort ( s , s + n ) ;

		int head = n - 1 ; // not sure
		int tail = n / 2 - 1 ; // work on 

		while ( tail >= 0 ) {

			if ( 2 * s [ tail ] <= s [ head ] ) {

				tail -- ;
				head -- ;
			}
			else {

				tail -- ;
			}
		}

		cout << head + 1 << endl ;
	}

	return 0 ;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值