NOIp2018D1T1 积木大赛 【思维】

题目传送门

感觉不是很难,但是需要一些思考...

可以发现,贪心地向尽量大的区间添加,但是存在一些比较小的数,它们不需要再加了,就会从那个地方断成两个区间。所以刚开始想到的做法就是统计每一种数的数量,每一次加过之后就能知道现在的一排积木被分成了多少段,每一段都要单独来加一次。

但是,存在整个区间都不需要再加的情况,这个时候这种方法还是会把这个区间再加一次。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<vector>
 4 #include<cstring>
 5 #include<queue>
 6 #include<map>
 7 #include<iostream>
 8 #include<stack>
 9 using namespace std;
10 #define ll long long
11 #define INF 0x3f3f3f3f
12 #define N 10005
13 int rd()
14 {
15     int f=1,s=0;char c=getchar();
16     while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
17     while(c>='0'&&c<='9'){s=(s<<3)+(s<<1)+(c^48);c=getchar();}
18     return f*s;
19 }
20 int n,cnt[N];
21 ll ans=0;
22 int main() 
23 {
24     int n=rd(),maxx=0;
25     for(int i=1;i<=n;i++)
26     {
27         int tmp=rd();
28         maxx=max(maxx,tmp);
29         if(i!=1&&i!=n) cnt[tmp]++;
30     }
31     int seg=1;
32     for(int i=1;i<=maxx;i++)
33     {
34         ans+=seg;
35         seg=seg-1+cnt[i]+1;
36     }
37     printf("%lld
",ans);
38     return 0;
39 }
Code

我们发现,一个区间最终需要加的次数等于这个区间中的最大值。把整个数列从递减的地方断开,分成若干个区间。区间中的最大值决定了区间被加的次数,而这个区间中的最小值也很重要,如果前面有数大于最小值的话,这个区间被加的次数的前 最小值 次都可以和上一个区间合并,可以省去 最小值 次。

就做完啦。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<vector>
 4 #include<cstring>
 5 #include<queue>
 6 #include<map>
 7 #include<iostream>
 8 #include<stack>
 9 using namespace std;
10 #define ll long long
11 #define INF 0x3f3f3f3f
12 #define N 10005
13 int rd()
14 {
15     int f=1,s=0;char c=getchar();
16     while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
17     while(c>='0'&&c<='9'){s=(s<<3)+(s<<1)+(c^48);c=getchar();}
18     return f*s;
19 }
20 int n;
21 ll ans=0;
22 int last=0;
23 int main() 
24 {
25     int n=rd();
26     for(int i=1;i<=n;i++)
27     {
28         int tmp=rd();
29         if(tmp<last) ans+=last,ans-=tmp,last=tmp;
30         else last=tmp;
31     }
32     ans+=last; 
33     printf("%lld
",ans);
34     return 0;
35 }
Code
原文地址:https://www.cnblogs.com/lyttt/p/11845382.html