洛谷 P1969 积木大赛
题目描述
春春幼儿园举办了一年一度的“积木大赛”。今年比赛的内容是搭建一座宽度为n的大厦,大厦可以看成由n块宽度为1的积木组成,第i块积木的最终高度需要是hi。
在搭建开始之前,没有任何积木(可以看成n块高度为 0 的积木)。接下来每次操作,小朋友们可以选择一段连续区间[l, r],然后将第第 L 块到第 R 块之间(含第 L 块和第 R 块)所有积木的高度分别增加1。
小 M 是个聪明的小朋友,她很快想出了建造大厦的最佳策略,使得建造所需的操作次数最少。但她不是一个勤于动手的孩子,所以想请你帮忙实现这个策略,并求出最少的操作次数。
输入输出格式
输入格式:
输入文件为 block.in
输入包含两行,第一行包含一个整数n,表示大厦的宽度。
第二行包含n个整数,第i个整数为hi 。
输出格式:
输出文件为 block.out
仅一行,即建造所需的最少操作数。
输入输出样例
5 2 3 4 1 2
输出样例#1:
5
说明
【样例解释】
其中一种可行的最佳方案,依次选择
[1,5] [1,3] [2,3] [3,3] [5,5]
【数据范围】
对于 30%的数据,有1 ≤ n ≤ 10;
对于 70%的数据,有1 ≤ n ≤ 1000;
对于 100%的数据,有1 ≤ n ≤ 100000,0 ≤ hi≤ 10000。
思路:
这道题很深,你可以做的很麻烦,也可以做的很简单,你都认为那是正解。
我就想了很多思路,然后用了最麻烦的方法。。但至少练习了一下倍增
1递归去做
#include<iostream> #include<cstdio> #include<queue> #include<algorithm> #include<vector> #include<cmath> #include<ctime> using namespace std; const int N=100009; int a[N]; int n; int f1[N][20],F;//zhi int f2[N][20];//where long long ans; inline void work(int L,int R,int tot) { if(L==R) { ans+=a[L]-tot; return ; } if(L>R) return ; int F=(log2(R-L+1)/log2(2)); int minn,minw; if(f1[L][F]<=f1[R-(1<<F)+1][F]) minn=f1[L][F],minw=f2[L][F]; else minn=f1[R-(1<<F)+1][F],minw=f2[R-(1<<F)+1][F]; ans+=minn-tot; work(L,minw-1,minn);work(minw+1,R,minn); return ; } int main() { scanf("%d",&n); F=(log2(n)/log2(2)); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); f1[i][0]=a[i]; f2[i][0]=i; } for(int j=1;j<=F;j++) for(int i=1;i<=n;i++) { if(f1[i][j-1]<=f1[i+(1<<(j-1))][j-1]) f1[i][j]=f1[i][j-1],f2[i][j]=f2[i][j-1]; else f1[i][j]=f1[i+(1<<(j-1))][j-1],f2[i][j]=f2[i+(1<<(j-1))][j-1]; } work(1,n,0); cout<<ans<<endl; return 0; }
2有点贪心吧,我也说不清
就是如果后一个比前个,大就要加它们的差。
#include<iostream> #include<cstdio> #include<queue> #include<algorithm> #include<vector> #include<cmath> #include<ctime> using namespace std; const int N=100009; int x,last,n; long long ans; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&x); if(x>last) ans+=x-last; last=x; } cout<<ans; return 0; }