P1969积木大赛

这是一到洛谷的题目:https://www.luogu.com.cn/problem/P1969

在搭建开始之前,没有任何积木(可以看成nnn块高度为000的积木)。接下来每次操作,小朋友们可以选择一段连续区间[l,r][l, r][l,r],然后将第第L L L块到第 RRR 块之间(含第L LL 块和第 RR R块)所有积木的高度分别增加111。

小M M M是个聪明的小朋友,她很快想出了建造大厦的最佳策略,使得建造所需的操作次数最少。但她不是一个勤于动手的孩子,所以想请你帮忙实现这个策略,并求出最少的操作次数。

一看到这道题,我是这样想的,找到一段中的最小值,然后每个数都减去最小值,ans加上最小值,一开始没发现这是一种递归思想(我太菜了),一段一段的。后来看了别人家的题解,才恍然大悟原来可以这样啊。那到底是怎么样的呢?首先这是一种递归的思想,我们一开始可以先从1到n开始,先是找到它们之中的最小值,也就是将它们全部历经一边找最小值,然后将在这一段上的数减去这个最小值min,在这之后就可以进行下一步的递归了,将1~n划分为两段,一是1~min-1,二是min+1~n,因为min这个数已经被减到0,所以可以不管它了,就这样递归下去。它的跳出条件就是before  >=  end 这样就说明中间的已经处理完了,还剩下了一个所以ans += num[before] ,还需要注意的是,因为我们找的是最小值,然后再减去最小值,所以无法避免的是,在最边上会有0的情况,所以我们可以再加上一个条件来判断;

看代码  这里的minn和index注意用局部变量,要不然容易错。

P1969积木大赛
 1 #include <cstdio>
 2 #include <iostream>
 3 
 4 using namespace std;
 5 const int inf = 0x3f3f3f3f;
 6 const int ma = 1e5 + 10;
 7 int ans,n,num[ma];
 8 
 9 void slove(int bf,int en)
10 {
11     if(bf >= en)
12     {
13         ans += num[bf];
14         return ;
15     }
16     if(num[bf] == 0)
17     {
18         slove(bf+1,en);return ;
19     }
20     if(num[en] == 0)
21     {
22         slove(bf,en-1);return ;
23     }
24     int minn = num[bf];
25     int index = bf;
26     for(int i = bf;i <= en;i++)
27         if(num[i] < minn)
28             minn = num[i],index = i;
29     for(int i = bf;i <= en;i++)
30         num[i] -= minn;
31     ans += minn;
32     slove(bf,index-1);
33     slove(index+1,en);
34 }
35 
36 int main()
37 {
38     scanf("%d",&n);
39     for(int i = 1;i <= n;i++)
40         scanf("%d",&num[i]);
41     int minn = inf;
42     int index;
43     for(int i = 1;i <= n;i++)
44     {
45         if(minn > num[i])
46             minn = num[i],index = i;
47     }
48     ans += minn;
49     for(int i = 1;i <= n;i++)
50         num[i] -= minn;
51     slove(1,index-1);
52     slove(index+1,n);
53     printf("%d",ans);
54     return 0;
55 }
View Code

 

如果真的理解了这道题目,你就会发现根本都不用这么麻烦。我们在这里建大厦,那么我们可以从第一个开始建,所以ans += num[1] ,现在已经建完了第一座大赛,下一个是第二座大厦了,然后我们就可以比较一下,是第一座高还是第二座高,如果是第二座大厦高的话,我们只需要加上(num[2] - num[1] )就行了,因为再第一座再建造的是第二座大厦也可以一起建造,所以只剩下高的部分没建完;如果第二座大厦矮的话,在第一座还没建完的时候,第二座就已经竣工了。然后就是第三座和第二座相比较···第n-1和第n座相比较。然后答案就出来了。这样建造的即使最少的操作数。因为这样保证了连续性。

看代码:

P1969积木大赛
 1 #include <cstdio>
 2 #include <iostream>
 3 
 4 using namespace std;
 5 const int ma = 1e5 + 10;
 6 int n,num[ma];
 7 
 8 int main()
 9 {
10     scanf("%d",&n);
11     for(int i = 1;i <= n;i++)
12         scanf("%d",&num[i]);
13     int ans = num[1];
14     for(int i = 1;i < n;i++)
15     {
16         if(num[i+1] > num[i])
17             ans += num[i+1] - num[i];
18     }
19     printf("%d",ans);
20     return 0;
21 }
View Code

 

上一篇:迭代硬阈值类算法总结||IHT/NIHT/CGIHT/HTP


下一篇:python基础篇-文件(读取,操作,关闭)