wenbao与单调栈
单调栈还是挺厉害的,将n方的复杂度降为n,66666
看了别人的博客和代码慢慢理解了其中的奥妙。。自己写的第一个单调栈,
1 #include <bits/stdc++.h> 2 using namespace std; 3 int a[50], le[50], lo[50]; 4 int main(){ 5 int n, num = 0, l, r, m = -1; 6 scanf("%d", &n); 7 for(int i = 1; i <= n; ++i){ 8 scanf("%d", a+i); 9 } 10 a[0] = -3, a[n+1] = -1; 11 for(int i = 1; i <= n+1; ++i){ 12 if(a[i] > a[lo[num]]){ 13 le[i] = i, lo[++num] = i; 14 continue; 15 }else if(a[i] == a[lo[num]]){ 16 continue; 17 } 18 while(a[i] < a[lo[num]]){ 19 int x = a[lo[num]]*(i-le[lo[num]]); 20 if(x > m){ 21 m = x, l = le[lo[num]], r = i-1; 22 } 23 le[i] = le[lo[num]]; 24 --num; 25 } 26 lo[++num] = i; 27 } 28 printf("%d : %d - > %d\n", m, l, r); 29 return 0; 30 }
升级版
1 #include <bits/stdc++.h> 2 using namespace std; 3 int a[50], s[50]; 4 int main(){ 5 int n, num = 0, l, r, m = -1; 6 scanf("%d", &n); 7 for(int i = 1; i <= n; ++i){ 8 scanf("%d", a+i); 9 } 10 a[0] = -3, a[n+1] = -1; 11 for(int i = 1; i <= n+1; ++i){ 12 while(a[i] < a[s[num]]){ 13 int x = a[s[num]] * (i-1-s[num-1]); 14 if(x > m){ 15 m = x, l = s[num-1]+1, r = i-1; 16 } 17 -- num; 18 } 19 s[++num] = i; 20 } 21 printf("%d : %d - > %d\n", m, l, r); 22 return 0; 23 }
思维真是好东西。。。。。。
http://poj.org/problem?id=2796
输入:
6 3 1 6 4 5 2
输出
60 3 5
1 #include <stdio.h> 2 #define ll long long 3 const int maxn = 1e5+2; 4 ll sum[maxn], cnt, m = -1; 5 int a[maxn], s[maxn], n, num, l, r; 6 int main(){ 7 int n; 8 scanf("%d", &n); 9 for(int i = 1; i <= n; i++) scanf("%d", a+i), sum[i] = sum[i-1] + a[i]; 10 a[0] = -3, a[n+1] = -1; 11 for(int i = 1; i <= n+1; i++){ 12 while(a[i] < a[s[num]]){ 13 cnt = a[s[num]] * (sum[i-1] - sum[s[num-1]]); 14 if(cnt > m){ 15 m = cnt, l = s[num-1]+1, r = i-1; 16 } 17 --num; 18 } 19 s[++num] = i; 20 } 21 printf("%lld\n%d %d\n", m, l, r); 22 return 0; 23 }
http://poj.org/problem?id=3494
找矩阵中1最多的子矩阵
1 #include <iostream> 2 #include <stdio.h> 3 using namespace std; 4 const int maxn = 2005; 5 int b[maxn][maxn], s[maxn]; 6 int main(){ 7 int n, m, x; 8 while(~scanf("%d%d", &n, &m)){ 9 int mx = -1; 10 for(int i = 1; i <= n; ++i){ 11 for(int j = 1; j <= m; ++j){ 12 scanf("%d", &x); 13 if(x & 1) b[i][j] = b[i-1][j] + 1; 14 else b[i][j] = 0; 15 } 16 } 17 for(int i = 1; i <= n; ++i){ 18 int num = 0; 19 b[i][0] = -3, b[i][m+1] = -1; 20 for(int j = 1; j <= m+1; ++j){ 21 while(b[i][s[num]] > b[i][j]){ 22 int x = b[i][s[num]] * (j - 1 - s[num-1]); 23 if(mx < x) mx = x; 24 -- num; 25 } 26 s[++num] = j; 27 } 28 } 29 printf("%d\n", mx); 30 } 31 return 0; 32 }
http://poj.org/problem?id=3250
计算能看到牛的个数和(每只牛都往右看且只能看到小于自己的牛)
自己写的
1 #include <iostream> 2 #include <stdio.h> 3 using namespace std; 4 #define ll long long 5 const ll INF = 1e9+10; 6 const int maxn = 80009; 7 int a[maxn], s[maxn], n; 8 unsigned long long m = 0; 9 int main(){ 10 int num = 0, n; 11 scanf("%d", &n); 12 for(int i = 1; i <= n; i++){ 13 scanf("%d", a+i); 14 } 15 a[0] = INF+1, a[n+1] = INF; 16 for(int i = 1; i <= n+1; i++){ 17 while(a[s[num]] <= a[i]){ 18 m += (i-1-s[num]); 19 -- num; 20 } 21 s[++num] = i; 22 } 23 printf("%u\n", m); 24 return 0; 25 }
参考别人的代码。6666666只需要一个栈数组就好,,每次栈里面的元素就是可以看到当前牛的个数,因为栈里面的元素是严格降序排列的。。
1 #include <stdio.h> 2 #include <iostream> 3 int s[80003]; 4 int main(){ 5 int n, x, num = 0; 6 long long sum = 0; 7 scanf("%d", &n); 8 for(int i = 0; i < n; ++i){ 9 scanf("%d", &x); 10 while(num > 0 && s[num] <= x) --num; //计算每头牛被看到的次数 11 sum += num; 12 s[++num] = x; 13 } 14 printf("%lld\n", sum); 15 return 0; 16 }
http://qscoj.cn/problem/11/
括号匹配求字长的匹配区间
1 #include <stdio.h> 2 #include <iostream> 3 #include <string.h> 4 using namespace std; 5 char str[100009]; 6 int s[100009]; 7 int main(){ 8 int n; 9 scanf("%d", &n); 10 while(n--){ 11 scanf("%s", str); 12 int num = 0, sum = 0; 13 int len = strlen(str); 14 str[len] = '*', str[len+1] = '#'; 15 s[0] = len+1; 16 for(int i = 0; i <= len; ++i){ 17 if(str[s[num]] == '(' && str[i] == ')'){ 18 num --; 19 }else{ 20 if(num == 0) sum = max(sum, i); 21 else sum = max(sum, i - s[num]-1); 22 s[++num] = i; 23 } 24 } 25 printf("%d\n", sum); 26 } 27 return 0; 28 }
只有不断学习才能进步!