哎~又被虐了
還是好好總結下下吧。
題目連接:http://codeforces.com/contest/466/problem/B
思路:Let’s assume that a ≤ b.
First of all, let’s consider the situation when we can already accommodate all the students. If 6·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
思路: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]
.
Complexity: O(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;
}
只有更加地努力,纔不要一直菜下去!
我知道會很艱難,但是不痛苦就不會有成長。把人生的一切都當做經歷吧,只有經歷得越多,心靈纔會更加豐富,去體驗吧、經歷吧!