I - Fence Repair
已知切割一块长度为 M 的木板(将其一分为二),其消耗的能量为 M。
请问,将一块长度为 X 的木板切割成 N 块(1≤ N ≤ 20000),且第 i 块长度为 Li (1≤ i ≤ N, 1≤ Li ≤50000 , L1+L2+…+LN= X) ,所需消耗的最小能量是多少?
Input
第一行为切割后木板的块数 N 。
之后的 N 行,第 i 行表示第 i 块木板的长度 Li 。
Output
输出一个整数,表示所需消耗的最小能量。
Sample Input
4
3
4
5
6
Sample Output
36
Hint
对于测试样例,X=3+4+5+6=18。
第一次切割,将长度为18的木板切割成两块:18=11+7,消耗能量为18;
第二次切割,将长度为11的木板切割成两块:11=5+6,消耗能量为11;
第三次切割,将长度为7的木板切割成两块:7=3+4,消耗能力为7。
总的消耗能量为18+11+7=36,为最小消耗能量。
Note
在此题中,请注意不要使用头文件 “bits/stdc++.h” 。
这题不是很难,贪心算法,刚开始我是想,一个长度为N的木块,不管你在哪个地方切,消耗都是N
所以在哪切,并不会影响当前的消耗,而是会影响后面的消耗,然后
一刀下去我们要从中间切,把一个木块变成两个木块,然后短的那块要比长的那块切的多(短的切出来的木条数量要多余长的那条),这样接下来切的消耗才会是当前最小,然后一直这样,可以求出整体最小。
举个例子:
假设我们要把木头切成如上几块,第一刀从中间切下去有两种情况:
第一种情况要比第二种情况好
因为第一种短的那个是 1,2,3 ,有三块,长的是 4,5 ,是两块,然后长的再切一刀,短的再切两刀就行了。
第二种长的是三块: 3,4,5 ,长的切两刀 肯定比 短的切两刀 消耗大。
然后就是代码实现,这样要用递归,然后题目数据较大, 递归肯定超时 或者会 栈内存溢出 ,所以我们可以反过来逆推:
按照这个切法,最后一刀下去,肯定是把最短的那块切成两块
我们可以把 最小的 和 次小 的合并,就能得到切它们两块时的消耗
然后再把 最小的 和 次小 的合并,然后把消耗累加起来,就能得到最终答案
AC代码
#include <iostream>
#include <vector>
#include <queue>
typedef long long ll;
using namespace std;
int main()
{
priority_queue<int, vector<int>, greater<int>> prique;
int n, value;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> value;
prique.push(value);
}
ll sum = 0, a, b;
for (int i = 0; i < n - 1; i++)
{
a = prique.top(), prique.pop();
b = prique.top(), prique.pop();
sum += a + b;
prique.push(a + b);
}
cout << sum << endl;
return 0;
}
这里用到了 优先队列,就不必要自己去排序了,优先队列基于 二叉堆 实现的。
C - Rails
There is a famous railway station in PopPush City. Country there is incredibly hilly. The station was built in last century. Unfortunately, funds were extremely limited that time. It was possible to establish only a surface track. Moreover, it turned out that the station could be only a dead-end one (see picture) and due to lack of available space it could have only one track.
The local tradition is that every train arriving from the direction A continues in the direction
B with coaches reorganized in some way. Assume that the train arriving from the direction A has
N ≤ 1000 coaches numbered in increasing order 1, 2, . . . , N. The chief for train reorganizations must
know whether it is possible to marshal coaches continuing in the direction B so that their order will
be a1.a2, . . . , aN . Help him and write a program that decides whether it is possible to get the required
order of coaches. You can assume that single coaches can be disconnected from the train before they
enter the station and that they can move themselves until they are on the track in the direction B. You
can also suppose that at any time there can be located as many coaches as necessary in the station.
But once a coach has entered the station it cannot return to the track in the direction A and also once
it has left the station in the direction B it cannot return back to the station.
Input
The input file consists of blocks of lines. Each block except the last describes one train and possibly
more requirements for its reorganization. In the first line of the block there is the integer N described
above. In each of the next lines of the block there is a permutation of 1, 2, . . . , N. The last line of the
block contains just ‘0’.
The last block consists of just one line containing ‘0’.
Output
The output file contains the lines corresponding to the lines with permutations in the input file. A line
of the output file contains ‘Yes’ if it is possible to marshal the coaches in the order required on the
corresponding line of the input file. Otherwise it contains ‘No’. In addition, there is one empty line after
the lines corresponding to one block of the input file. There is no line in the output file corresponding
to the last “null” block of the input file.
Sample Input
5
1 2 3 4 5
5 4 1 2 3
0
6
6 5 4 3 2 1
0
0
Sample Output
Yes
No
Yes
模拟题,用栈和队列模拟,不过刚开始我不想模拟,因为这个出车站的顺序和进车站的顺序是有规律的:
出站就是将进站顺序的某一段反转而已,所以,我们可可以按照反转的规律,将他们分成几段:
这里分成了三段,可以看出,三段里,对应的 进站编号 和 出站编号 相加都是相等的,因为他们是对称的。
第一段:1+3 = 2+2 = 3+1
第二段:4+4
第三段:5+5
所以,根据这个就能判断出站顺序成不成立
可是过不了,可能是那个地方的细节没处理好,下面是这个思路的代码:
#include <iostream>
using namespace std;
const int maxn = 100000000;
int array[maxn];
int main(void)
{
int n;
while ((cin >> n) && n != 0)
{
while (cin >> array[1] && array[1] != 0)
{
for (int i = 2; i <= n; i++)
cin >> array[i];
int begin = 1, end = array[begin], sum = begin + end;
while (begin <= end && end <= n)
{
while (begin <= end && begin + array[begin] == sum)
begin++;
if (begin > end)
begin = end + 1, end = array[begin], sum = begin + end;
else
break;
}
if (!(begin <= end && end <= n))
cout << "Yes" << endl;
else
cout << "No" << endl;
}
cout << endl;
}
return 0;
}
最后还是用了模拟,下面是AC代码:
#include <iostream>
#include <stack>
using namespace std;
const int maxn = 100000000;
int B[maxn];
int main(void)
{
int n;
while ((cin >> n) && n != 0)
{
while (cin >> B[1] && B[1] != 0)
{
for (int i = 2; i <= n; i++)
cin >> B[i];
stack<int> sta;
int i, index;
for (i = index = 1; i <= n; i++)
{
sta.push(i);
while (sta.size() && sta.top() == B[index])
sta.pop(), index++;
}
if (sta.size())
cout << "No" << endl;
else
cout << "Yes" << endl;
}
cout << endl;
}
return 0;
}