积木大赛

题目大意:

给定一个长度为n的序列,每一次可以选择一段连续的区间,将该区间每一个数都减1,每一个数的最小值为0,问最少需要执行多少次该操作。

虽然正解比较好像,但是我优化优化了暴力发现也过了。。。

朴素算法80分:

每一次从头找到第一个不为0的数,往后一直找到第一个0,他的前一个数如果是0,那么就代表可以结束了,如果不是,lr区间每一项就减去该区间最小值,并且ans++。

正确性还是比较显然的,不知道的话可以在下面留言。

随便搞搞100分:

由于n已经达到10的五次方,这种枚举方式很有可能会超时,我们考虑优化:

我们每一次记录一下找到的l,这个l的位置代表从头到这的数都是0,那么我们下一次枚举时从这里开始枚举就好了。

正解:

贪心策略:每当我们扫到一个数,如果它大于前一个数答案就加上差值,正确性?

这是比较显然的,如果比前一个数小,那么减前一个数时就可以顺便把他减掉,如果大于则还得自己减。

最后,附上本题代码:

随便搞搞:跑的还是挺快的,就比正解慢了4ms

 1 #include<cstdio>
 2 #define maxn 100000
 3 using namespace std;
 4 
 5 int n,a[maxn+5],ans,last;
 6 
 7 int main()
 8 {
 9     scanf("%d",&n);
10     for(int i=1;i<=n;i++)
11     {
12         scanf("%d",&a[i]);
13     }
14     while(1)
15     {
16         int l=0,r=n,minn=10005;
17         for(int i=last;i<=n;i++)
18         {
19             if(a[i]>0)
20             {
21                 l=i;
22                 last=l;
23                 break;
24             }
25         }
26         if(l==0)
27         {
28             break;
29         }
30         for(int i=l;i<=n;i++)
31         {
32             if(a[i]<=0)
33             {
34                 r=i-1;
35                 break;
36             }
37             if(a[i]<minn)
38             {
39                 minn=a[i];
40             }
41         }
42         for(int i=l;i<=r;i++)
43         {
44             a[i]-=minn;
45         }
46         ans+=minn;
47     }
48     printf("%d
",ans);
49     return 0;
50 }

正解代码:

 1 #include <iostream>
 2 using namespace std;
 3 int main()
 4 {
 5     int n,a,last=0,ans=0;
 6     cin>>n;
 7     for(int i=1;i<=n;i++)
 8     {
 9         cin>>a;
10         if(a>last) ans+=(a-last);
11         last=a;
12     }
13     cout<<ans<<endl;
14 }
原文地址:https://www.cnblogs.com/yufenglin/p/10586167.html