http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1215
题目来源: Javaman
基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题
收藏
关注
N个整数组成的数组,定义子数组a[i]..a[j]的宽度为:max(a[i]..a[j]) - min(a[i]..a[j]),求所有子数组的宽度和。
Input
第1行:1个数N,表示数组的长度。(1 <= N <= 50000) 第2 - N + 1行:每行1个数,表示数组中的元素(1 <= A[i] <= 50000)
Output
输出所有子数组的宽度和。
Input示例
5 1 2 3 4 5
Output示例
20感觉很经典的题目。 首先我们不可能枚举出所有的子区间,显然时空是不允许的,那就要从元素入手,我们只要知道每个元素被作为最大最小值得次数答案就出来了,问题转化为求元素作为最值的次数。可以找到当前元素作为最大/小值时对应的最大的区间左右端点,然后组合计算一下就是答案了。找这个左右端点时可以用单调栈也可以迭代搜索,stl貌似要慢一些。 正确性在于找端点时满足决策单调性,例如找最大值左端点时,这个元素左侧的元素如果大于他,那显然左端点就是他本身了,此时就是一个单调递减栈,大于栈顶元素时左端点就可以用栈顶元素的左端点代替; 总之就一句话,大于左侧的元素,一定大于所有左侧元素能大于的元素。 还有就是第一次WA了因为重复计算了, 只要稍微修改一下为左侧不严格右侧严格的查找就好了。
1 #include <iostream> 2 #include<algorithm> 3 #include<stack> 4 #include<cstdio> 5 using namespace std; 6 typedef long long LL; 7 const int MAX = 50005; 8 int a[MAX], l1[MAX], r1[MAX], l2[MAX], r2[MAX]; 9 int maxt[MAX], mint[MAX]; 10 stack<int>S; 11 int main() 12 { 13 int N, i, j, k; 14 scanf("%d", &N); 15 for (i = 1;i <= N;++i) scanf("%d", a + i); 16 for (i = 1;i <= N;++i) 17 { 18 if (S.empty() || a[i] < a[S.top()]) { 19 l1[i] = i; 20 S.push(i); 21 } 22 else { 23 while (!S.empty() && a[S.top()] <= a[i]) { 24 l1[i] = l1[S.top()]; 25 S.pop(); 26 } 27 S.push(i); 28 } 29 }while (!S.empty()) S.pop(); 30 for (i = N;i >=1;--i) 31 { 32 if (S.empty() || a[i] <= a[S.top()]) { 33 r1[i] = i; 34 S.push(i); 35 } 36 else { 37 while (!S.empty() && a[S.top()] < a[i]) { 38 r1[i] = r1[S.top()]; 39 S.pop(); 40 } 41 S.push(i); 42 } 43 }while (!S.empty()) S.pop(); 44 for (i = 1;i <= N;++i) 45 { 46 maxt[i] += (r1[i]-l1[i])+(i-l1[i])*(r1[i]-i); 47 } 48 for (i = 1;i <= N;++i) 49 { 50 if (S.empty() || a[i] > a[S.top()]) { 51 l2[i] = i; 52 S.push(i); 53 } 54 else { 55 while (!S.empty() && a[S.top()] >=a[i]) { 56 l2[i] = l2[S.top()]; 57 S.pop(); 58 } 59 S.push(i); 60 } 61 }while (!S.empty()) S.pop(); 62 for (i = N;i>=1;--i) 63 { 64 if (S.empty() || a[i] >= a[S.top()]) { 65 r2[i] = i; 66 S.push(i); 67 } 68 else { 69 while (!S.empty() && a[S.top()] > a[i]) { 70 r2[i] = r2[S.top()]; 71 S.pop(); 72 } 73 S.push(i); 74 } 75 }while (!S.empty()) S.pop(); 76 for (i = 1;i <= N;++i) 77 { 78 mint[i] += (-l2[i]+r2[i])+(i-l2[i])*(r2[i]-i); 79 } 80 LL ans = 0; 81 for (i = 1;i <= N;++i) 82 { 83 ans += (LL)a[i] * (maxt[i]-mint[i]); 84 } 85 printf("%lld\n", ans); 86 return 0; 87 }
迭代:
1 #include <iostream> 2 #include<algorithm> 3 #include<stack> 4 #include<cstdio> 5 using namespace std; 6 typedef long long LL; 7 const int MAX = 50005; 8 int a[MAX], l1[MAX], r1[MAX], l2[MAX], r2[MAX]; 9 int maxt[MAX], mint[MAX]; 10 int main() 11 { 12 int N, i, j, k; 13 scanf("%d", &N); 14 for (i = 1;i <= N;++i) scanf("%d", a + i); 15 for (i = 1;i <= N;++i) { 16 l1[i] = r1[i] = i; 17 l2[i] = r2[i] = i; 18 } 19 for (i = 1;i <= N;++i) { 20 while (l1[i] != 1 && a[i] >= a[l1[i] - 1]) 21 l1[i] = l1[l1[i]-1]; 22 while (l2[i] != 1 && a[i] <= a[l2[i] - 1]) 23 l2[i] = l2[l2[i] - 1]; 24 } 25 for (i = N;i >= 1;--i) { 26 while (r1[i] != N&&a[i] > a[r1[i] + 1]) 27 r1[i] = r1[r1[i] + 1]; 28 while (r2[i] != N&&a[i] < a[r2[i] + 1]) 29 r2[i] = r2[r2[i] + 1]; 30 } 31 LL ans = 0; 32 for (i = 1;i <= N;++i) { 33 ans += (LL)a[i] * ((r1[i] - l1[i]) + (i - l1[i])*(r1[i] - i)- (-l2[i] + r2[i]) - (i - l2[i])*(r2[i] - i)); 34 } 35 cout << ans << endl; 36 //system("pause"); 37 return 0; 38 }
时间: 2024-11-03 02:53:18