题面:
C.New Year Book Reading
Input file: standard input
Output file: standard output
Time limit: 2 second
Memory limit: 256 megabytes
New Year is coming, and Jaehyun decided to read many books during 2015, unlike this year. He has n books numbered by integers from 1 to n. The weight of the i-th (1 ≤ i ≤ n) book is wi.
As Jaehyun's house is not large enough to have a bookshelf, he keeps the n books by stacking them vertically. When he wants to read a certain book x, he follows the steps described below.
- He lifts all the books above book x.
- He pushes book x out of the stack.
- He puts down the lifted books without changing their order.
- After reading book x, he puts book x on the top of the stack.
He decided to read books for m days. In the j-th (1 ≤ j ≤ m) day, he will read the book that is numbered with integer bj (1 ≤ bj ≤ n). To read the book, he has to use the process described in the paragraph above. It is possible that he decides to re-read the same book several times.
After making this plan, he realized that the total weight of books he should lift during m days would be too heavy. So, he decided to change the order of the stacked books before the New Year comes, and minimize the total weight. You may assume that books can be stacked in any possible order. Note that book that he is going to read on certain step isn't considered as lifted on that step. Can you help him?
Input
The first line contains two space-separated integers n (2 ≤ n ≤ 500) and m (1 ≤ m ≤ 1000) — the number of books, and the number of days for which Jaehyun would read books.
The second line contains n space-separated integers w1, w2, ..., wn (1 ≤ wi ≤ 100) — the weight of each book.
The third line contains m space separated integers b1, b2, ..., bm (1 ≤ bj ≤ n) — the order of books that he would read. Note that he can read the same book more than once.
Output
Print the minimum total weight of books he should lift, which can be achieved by rearranging the order of stacked books.
Example
Input
3 5
1 2 3
1 3 2 3 1
Output
12
Note
Here's a picture depicting the example. Each vertical column presents the stacked books.
题目描述:
新年来了,主人公想要在2015年读很多书,每本书编号为1-N,wi为每本书的重量。由于空间太小,所以主人公只好把书全都叠在一起。当主人公想拿出一本书时,要把这本书上面的书一起搬出来,取出这本书后再把搬出来的书一起放回去。主人公要看m天的书,每天要拿出一本书出来看。主人公不想每次拿书时搬太重的书,所以想先把书按一定的顺序放好,然后使得自己在这m天内总共搬出的书的重量最小。求:总共搬出的书的重量最小是多少?
题目分析:
这道题用的方法是贪心+模拟。首先,要确定总共搬出的书的重量最小,是不是要先确定这些书该怎么放?也就是要找到初始的栈。我们可以一个一个按顺序地想。我们想想主人公第一天要看的的书 b1 应该放在哪里。假设b1放在这个栈的其中一个位置:
当我们取出b1,看完后放回原位是这样的:
那么,我们可以进一步减少拿出b1时,搬书的重量吗?答案是直接把b1放到栈的顶部。原因:过了第一天后,无论栈里面书的顺序怎样放,b1肯定是放在顶部的。换句话说,无论b1之前放在栈的什么位置,反正b1过了第一天后都要放在栈的最顶部(题目说的),也就是b1放在栈的位置是不会影响后面的过程(后面的过程:拿b2,b3,b4等等的书,按时间顺序拿),所以,就要使b1的位置达到最优,也就是放在栈的顶部,才能使结果最优,也就是总的搬书重量最小,理解这个是关键。接下来我们考虑b2——第二天要看的书要放在哪里。首先,肯定是不能放在最顶部的,原因之前说了。那么,应该放在哪里呢?大家应该想到了:放在b1的下面:
想法和前面是一样的:假设b2放到其他位置(b1下面的其他位置),那么,把b2取出来后,第二天看完b2肯定是要把b2放到栈的最顶部。无论把b2放到栈的哪个位置都是对后面过程没有影响的,所以,我们要使得当前要搬的书的重量减小,就要放到紧接着b1的下面。有的人可能到这里会有些疑惑,这样放为什么不行:
不应该是这样放初始的栈才能使b2最优吗?这里可能有的人被绕晕了。其实,这样摆放不行之前已经说过了(博主真啰嗦 (╯▔皿▔)╯ ),不明白的同学可以看下面的模拟图(初始的栈:b2放在b1的上面):
(初始的栈:b1放在b2的上面):
我想,看完这个图大家都知道肯定是b1放在最上面才是最优的吧。(注意到第一天看完后b1是肯定放回顶部的)。
同理可得b3,b4等等都是按照这个规则来确定这些书在初始栈的位置。所以,我们的做法是:逐步从1-m遍历b1, b2, b3, ...., bm。当遍历到bi时,如果之前遍历过bi(注意bi是书的编号),也就是bi 属于 b1,b2,...,b(i-1),就不用考虑放入初始栈,否则就加入到初始栈里面。这里要注意的是,如果是用入栈的方式确定初始栈时,要注意这个栈倒过来才是我们想要的初始栈(因为我们是先确定顶部放什么书,当加入到栈时就会变成底部)。当然,这里的确定初始栈做法因人而异,大家也可以尝试用其他的做法。如果在这个初始栈中,不够n本书(也就是说主人公没有安排自己在2015年读完n本书),那么,剩余还没有安排位置的书,如果要放到初始栈的话,肯定是放在初始栈的底部(不读这些书肯定放在最下面啊),但是由于题目不是求这个具体的初始栈,所以,不需要把没有安排位置的书放到初始栈。最后,我们根据这个初始栈,来模拟题目的操作,算出总共每次要搬的书的重量。
AC代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <cmath> 5 #include <set> 6 #include <map> 7 #include <algorithm> 8 #include <utility> 9 using namespace std; 10 int w[505], b[1005]; 11 int temp[505], t; //辅助栈 12 int st[505], top; //初始栈 13 int vis[505]; //标记数组 14 15 int main(){ 16 int n, m; 17 cin >> n >> m; 18 for(int i = 1; i <= n; i++) cin >> w[i]; 19 for(int i = 1; i <= m; i++) cin >> b[i]; 20 21 for(int i = 1; i <= m; i++){ 22 if(!vis[b[i]]){ 23 vis[b[i]] = 1; //标记被访问过 24 temp[++t] = b[i]; //加入到辅助栈 25 } 26 } 27 28 while(t) st[++top] = temp[t--]; //倒过来就是初始栈了 29 30 int read; //当天要读的书 31 int res = 0; //结果 32 for(int i = 1; i <= m; i++){ //模拟 33 while(top){ //找书 34 if(st[top] == b[i]){ 35 read = b[i]; //找到要读的书 36 top--; 37 break; 38 } 39 res += w[st[top]]; //确定重量 40 temp[++t] = st[top--]; //搬书 41 } 42 while(t) st[++top] = temp[t--]; //搬回去 43 st[++top] = read; //把要读的书放回去 44 } 45 46 cout << res << endl; 47 return 0; 48 }