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