哎~又被虐了
还是好好总结下下吧。
题目连接: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;
}
只有更加地努力,才不要一直菜下去!
我知道会很艰难,但是不痛苦就不会有成长。把人生的一切都当做经历吧,只有经历得越多,心灵才会更加丰富,去体验吧、经历吧!