Codeforces Round #266 (Div. 2) B & C

哎~又被虐了

還是好好總結下下吧。


題目連接:http://codeforces.com/contest/466/problem/B

B. Wonder Room
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

The start of the new academic year brought about the problem of accommodation students into dormitories. One of such dormitories has a a × b square meter wonder room. The caretaker wants to accommodate exactly n students there. But the law says that there must be at least 6 square meters per student in a room (that is, the room for n students must have the area of at least 6n square meters). The caretaker can enlarge any (possibly both) side of the room by an arbitrary positive integer of meters. Help him change the room so as alln students could live in it and the total area of the room was as small as possible.

Input

The first line contains three space-separated integers na and b (1 ≤ n, a, b ≤ 109) — the number of students and the sizes of the room.

Output

Print three integers sa1 and b1 (a ≤ a1b ≤ b1) — the final area of the room and its sizes. If there are multiple optimal solutions, print any of them.

Sample test(s)
input
3 3 5
output
18
3 6
input
2 4 4
output
16
4 4

題意:有n個學生要住在a*b這麼大面積的房間裏,要求每個學生至少有6平方米的居住面積,也就是要找到這樣的a1和b1,使得6*n <= min{a1*b1},其中a<=a1 && b<=b1。注意!1 <= n, a, b <= 1e9

思路:Let’s assume that a ≤ b.

First of all, let’s consider the situation when we can already accommodate all the students. If n ≤ a·b then answer is a·b a b.

Otherwise, we have to increase one of the walls(maybe, both). Let’s do it in the following way: iterate the size of the smallest wall newa ( ), after that we can calculate the size of another wall as 
For all this newa and newb if b ≤ newb we choose such a pair that has the smallest area of a room.

Obviously to undestrand, that there is no point to consider  because we can decrease it and receive room of smaller area when we know that .

Complexity

最開始考慮的竟然是二分查找!被自己的機智嚇到了,可惜,準確度不行啊,還是得O(sqrt(n))的複雜度。

代碼:

#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
using namespace std;

void swap(__int64 *a, __int64 *b)
{
	__int64 tmp;
	tmp = *a;
	*a = *b;
	*b = tmp;
}

int main()
{
	__int64 n, a, b;
	cin >> n >> a >> b;
	if (6*n <= a*b)
	{
		cout << a*b << endl;
		cout << a << " " << b << endl;
	}
	else
	{
		bool flag = false;
		if (a > b)
		{
			swap(a, b);
			flag = true;
		}
		__int64 maxsq = 1e18;
		__int64 newa, newb;

		// 注意要向上取整!
		for (__int64 a1 = a; a1 <= ceil(sqrt(6.0*n)); a1++)
		{
			__int64 b1 = ceil(6.0*n/a1);
			// b1 <= 1e9 精度很重要
			if (b1 >= b && b1 <= 1e9 && a1*b1 <= maxsq)
			{
				newa = a1;
				newb = b1;
				maxsq = a1*b1;
			}
		}

		// 把交換了的長和寬再置換回來
		if (flag)
			swap(newa, newb);
		cout << maxsq << endl;
		cout << newa << " " << newb << endl;
	}

	return 0;
}


題目連接:http://codeforces.com/contest/466/problem/C

C. Number of Ways
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

You've got array a[1], a[2], ..., a[n], consisting of n integers. Count the number of ways to split all the elements of the array into three contiguous parts so that the sum of elements in each part is the same.

More formally, you need to find the number of such pairs of indices i, j (2 ≤ i ≤ j ≤ n - 1), that .

Input

The first line contains integer n (1 ≤ n ≤ 5·105), showing how many numbers are in the array. The second line contains n integers a[1],a[2], ..., a[n] (|a[i]| ≤  109) — the elements of array a.

Output

Print a single integer — the number of ways to split the array into three parts with the same sum.

Sample test(s)
input
5
1 2 3 0 3
output
2
input
4
0 1 -1 0
output
1
input
2
4 1
output
0

題意:有一個長度爲n的數組,把數組劃分爲連續的三個部分,要求三個部分之和相等,找出所有滿足這樣條件的劃分的個數。

思路:First of all, notice that if sum of all elements is equal S then sum of each of three parts is equal .

Therefore, if S is not divided by 3 — then answer is 0.
Otherwise, let’s iterate the end of first part i (1 ≤ i ≤ n - 2) and if sum of 1..i elements is equal  then it means that we have to add to the answer the amount of such j (i + 1 < j) that the sum of elements from j-th to n-tn also equals .

Let’s create an array cnt[], where cnt[i] equals 1, if the sum of elements from i-th to n-th equals  and 0 — otherwise. Now, to calculate the answer we have to find the sum cnt[j] + cnt[j+1] + ... + cnt[n] faster then O(n). There are a lot of required ways to do this, but the easiest one is to create a new additional array sums[] where in j-th element will becnt[j] + cnt[j+1] + ... + cnt[n]. It is easy to calculate in such way: sums[n] = cnt[n],sums[i] = sums[i+1] + cnt[i] (i < n).

Thus, we receive very simple solution: for each prefix of initial array 1..i with the sum that equals  we need to add to the answersums[i+2].

ComplexityO(n)

之前看了半天沒看明白,還是好好解釋下吧。

首先,假設所有元素之和爲S,那麼三個部分每部分之和都是S/3.

因此,凡是不能被3整除或者元素個數少於3個的輸出結果必然爲0.

在以上情況之外,我們的做法是首先遍歷這n個元素,找到前i個元素(0,1, .. , i-1)之和爲S/3;在滿足了前i個元素之和爲S/3的情況下,我們從第i+2個元素開始查找(因爲劃分爲三部分,至少有一個元素作爲第二部分的),使得從第j(i+1 <j<=n)個元素到第n個元素之和也爲S/3;如此一來,中間那部分的元素之和也必然爲S/3,也就找到了這樣一個滿足條件的劃分。

前i個元素之和爲S/3很好解決,算法的關鍵轉化爲找到從第j個元素到第n個元素之和也爲S/3。創建數組cnt[],若j-th到n-th之和爲S/3,則令cnt[j]=1,否則cnt[j]=0。那麼sums[j] = cnt[j]+cnt[j+1]+..+cnt[n]恰好爲j-th到n-th之和爲S/3的元素個數。關於sum[]的快速計算方法,令sums[n]=cnt[n],sums[j] = sums[j+1]+cnt[i]。

最後,滿足條件的劃分爲 cnt[i+2]+..+cnt[n] = sums[i+2].

代碼:

#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#define MAX 500010
using namespace std;

__int64 a[MAX];
__int64 cnt[MAX], sums[MAX];

int main()
{
	__int64 n;
	cin >> n;
	__int64 sum = 0;
	for (__int64 i = 0; i < n; i++)
	{
		cin >> a[i];
		sum += a[i];
	}

	if (n < 3 || sum % 3)
	{
		cout << "0" << endl;
		return 0;
	}

	// 初始化cnt[]
	__int64 revsum = 0;
	for (__int64 i = n-1; i >= 0; i--)
	{
		revsum += a[i];
		if (revsum == sum/3)
			cnt[i] = 1;
	}

	// dp計算sums[]
	sums[n-1] = cnt[n-1];
	for (__int64 i = n-2; i >= 0; i--)
		sums[i] = sums[i+1]+cnt[i];

	__int64 s = 0;
	__int64 ans = 0;
	// 依算法特性計算結果
	for (__int64 i = 0; i < n-2; i++)
	{
		s += a[i];
		if (s == sum/3)
			ans += sums[i+2];
	}

	cout << ans << endl;

	return 0;
}

只有更加地努力,纔不要一直菜下去!

我知道會很艱難,但是不痛苦就不會有成長。把人生的一切都當做經歷吧,只有經歷得越多,心靈纔會更加豐富,去體驗吧、經歷吧!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章