A - 最大矩形
给一个直方图,求直方图中的最大矩形的面积。例如,下面这个图片中直方图的高度从左到右分别是2, 1, 4, 5, 1, 3, 3, 他们的宽都是1,其中最大的矩形是阴影部分。
Input
输入包含多组数据。每组数据用一个整数n来表示直方图中小矩形的个数,你可以假定1 <= n <= 100000. 然后接下来n个整数h1, …, hn, 满足 0 <= hi <= 1000000000. 这些数字表示直方图中从左到右每个小矩形的高度,每个小矩形的宽度为1。 测试数据以0结尾。
Output
对于每组测试数据输出一行一个整数表示答案。
Sample Input
7 2 1 4 5 1 3 3
4 1000 1000 1000 1000
0
Sample Output
8
4000
分别用递增栈和递减栈记录每个矩形最左边和最右边,再计算每个矩形的面积,输出最大的面积
这里求矩形的最左边具体算法如下:创建一个堆,当它不空时,在输入矩形的面积之前,如果栈头的矩形高度比当前的矩形面积小,当前矩形的最左边对应栈头元素。求矩形的最右边也是如此。
#include<iostream>
#include<stdio.h>
#include<queue>
#include<stack>
using namespace std;
struct array0 {
int ii;//记录下标
int left;
int right;
int value;
long long s;
};
array0 a[100000];
int main()
{
stack<int> st;
stack<int> st1;
int n;
int i;
while (1)
{
// scanf("%d", &n);
cin >> n;
if (n == 0)
{
break;
}
for (i = 0;i < n;i++)
{
// scanf("%d", &a[i].value);
cin >> a[i].value;
a[i].ii = i;
//st只保存数组的下标
while (!st.empty() && a[st.top()].value >= a[i].value)
{
// cout << "下标为" << st.top() << "的元素会被弹出" << endl;
st.pop();
}
if (st.empty())
{
a[i].left = -1;
}
else
{
a[i].left = st.top();
// cout << "st.top().ii= " << st.top().ii << endl;
}
st.push(a[i].ii);
//cout << "a[" << i << "].value ="<<a[i].value<< " a[" << i << "].left = " << a[i].left << endl;
}
/
for (int j = n - 1;j >= 0;j--)
{
while (!st1.empty() && a[st1.top()].value >= a[j].value)
{
// cout << "st1.[" << st1.top() << "] 被弹出" << endl;
st1.pop();
}
if (st1.empty())
{
a[j].right = n;
}
else
{
a[j].right = st1.top();
}
st1.push(a[j].ii);
a[j].s = (long long)((long long)a[j].value *((long long)(a[j].right - a[j].left - 1)));
// cout << "a[" << j << "].right = " << a[j].right << endl;
// cout << "a[" << j << "].s = " << a[j].s << endl;
}
///
long long max = 0;
for (int j = 0;j < i;j++)
{
if (a[j].s >= max)
{
max = a[j].s;
}
}
cout << max << endl;
while (!st.empty())
{
st.pop();
}
while (!st1.empty())
{
st1.pop();
}
}
return 0;
}
B - TT’s Magic Cat
Thanks to everyone’s help last week, TT finally got a cute cat. But what TT didn’t expect is that this is a magic cat.
One day, the magic cat decided to investigate TT’s ability by giving a problem to him. That is select n cities from the world map, and a[i] represents the asset value owned by the i-th city.
Then the magic cat will perform several operations. Each turn is to choose the city in the interval [l,r] and increase their asset value by c. And finally, it is required to give the asset value of each city after q operations.
Could you help TT find the answer?
Input
The first line contains two integers n,q (1≤n,q≤2⋅105) — the number of cities and operations.
The second line contains elements of the sequence a: integer numbers a1,a2,…,an (−106≤ai≤106).
Then q lines follow, each line represents an operation. The i-th line contains three integers l,r and c (1≤l≤r≤n,−105≤c≤105) for the i-th operation.
Output
Print n integers a1,a2,…,an one per line, and ai should be equal to the final asset value of the i-th city.
Examples
Input
4 2
-3 6 8 4
4 4 -2
3 3 1
Output
-3 6 9 2
Input
2 1
5 -2
1 2 4
Output
9 2
Input
1 2
0
1 1 -8
1 1 -6
Output
-14
本题主要用了差分的方法,用一个数组首先只记录第一个元素,之后依次记录后一个元素与前一个元素的差值,只有在每次的l r c,中,在这个数组中第l个元素又比第l-1个元素大c,第r+1个元素比第r个元素小c.
#include<iostream>
#include<stdio.h>
#include<queue>
#include<stack>
#include<algorithm>
#include<math.h>
using namespace std;
long long a[300001];
long long b[300001];
int main()
{
for (int i = 0;i < 300001;i++)
{
b[i] = 0;
}
int n, q;
cin >> n >> q;//n代表了元素的个数。q代表操作的个数
for (int i = 1;i <= n;i++)
{
cin >> a[i];
if (i != 1)
{
b[i] = a[i] - a[i - 1];
}
else
{
b[i] = a[i];
}
}
for (int i = 0;i < q;i++)
{
int l, r;
long long c;
cin >> l >> r >> c;
b[l] = b[l] + c;
b[r + 1] = b[r + 1] - c;
}
long long sum = 0;
for (int i = 1;i <= n;i++)
{
sum += b[i];
cout << sum << " ";
}
return 0;
}
C - 平衡字符串
一个长度为 n 的字符串 s,其中仅包含 ‘Q’, ‘W’, ‘E’, ‘R’ 四种字符。
如果四种字符在字符串中出现次数均为 n/4,则其为一个平衡字符串。
现可以将 s 中连续的一段子串替换成相同长度的只包含那四个字符的任意字符串,使其变为一个平衡字符串,问替换子串的最小长度?
如果 s 已经平衡则输出0。
Input
一行字符表示给定的字符串s
Output
一个整数表示答案
Examples
Input
QWER
Output
0
Input
QQWE
Output
1
Input
QQQW
Output
2
Input
QQQQ
Output
3
Note
1<=n<=10^5
n是4的倍数
字符串中仅包含字符 ‘Q’, ‘W’, ‘E’ 和 ‘R’.
本题要计算当给出一串不平衡的字符串时,如何找到最短的序列替换成平衡的字符串。我们只需要找到一系列这样的序列(QWER在此序列之外的总数不大于0.25*字符串长度)。我用虚拟队列来求这样的序列,首先找到符合替换条件的序列,接着将序列的左区间不断右移,直至不符合要求,然后又将右区间右移直至符合要求,如此循环只到字符串末尾。
#include<cmath>
#include<map>
#include <algorithm>
#include<iostream>
#include<string>
using namespace std;
string st; //用来装字母
int begin0, end0;
map<char, int> mp;
int main()
{
begin0 = end0 = 0;
cin >> st;
int len = st.size();
for (int i = 0; i < 4;i++)
{
mp[i] = 0;
}
for (int i = 0; i < len ;i++)
{
mp[st[i]]++;
}
int n = len / 4;
if (mp[0] == n && mp[1] == n && mp[2] == n && mp[3] == n)
{
cout << 0 << endl;
return 0;
}
int result = len;
//int mm = 0;
while (end0 < len)
{
// cout << "mp['Q']=" << mp['Q'] << "mp['W']=" << mp['W'] << "mp['E']=" << mp['E'] << "mp['R']=" << mp['R'] << endl;
mp[st[end0]]--; //右移
bool key = 1;
if (mp['Q'] > n || mp['W'] > n || mp['E'] > n || mp['R'] > n)
{
key = 0;
}
while (key == 1 && begin0 < len)
{
//result记录当前符合要求的最短区间
result = min(result, end0 - begin0 + 1);
mp[st[begin0]]++; //左边界右移
// cout << "result = " << result << endl;
if (mp[st[begin0]] > n) //mp[i]中仅有st[begin0]变化
{
key = 0;
}
begin0++;
}
end0++; //移右框
}
cout << result << endl;
return 0;
}
D - 滑动窗口(C++和G++都交一下)
ZJM 有一个长度为 n 的数列和一个大小为 k 的窗口, 窗口可以在数列上来回移动. 现在 ZJM 想知道在窗口从左往右滑的时候,每次窗口内数的最大值和最小值分别是多少. 例如:
数列是 [1 3 -1 -3 5 3 6 7], 其中 k 等于 3.
Window position Minimum value Maximum value
[1 3 -1] -3 5 3 6 7 -1 3
1 [3 -1 -3] 5 3 6 7 -3 3
1 3 [-1 -3 5] 3 6 7 -3 5
1 3 -1 [-3 5 3] 6 7 -3 5
1 3 -1 -3 [5 3 6] 7 3 6
1 3 -1 -3 5 [3 6 7] 3 7
Input
输入有两行。第一行两个整数n和k分别表示数列的长度和滑动窗口的大小,1<=k<=n<=1000000。第二行有n个整数表示ZJM的数列。
Output
输出有两行。第一行输出滑动窗口在从左到右的每个位置时,滑动窗口中的最小值。第二行是最大值。
Sample Input
8 3
1 3 -1 -3 5 3 6 7
Sample Output
-1 -3 -3 -3 3 3
3 3 5 5 6 7
本题是找指定区间的最大值和最小值,我采用队列的方法,制定一个递增队列,一个递减队列。
在递增队列中,要保证当前被插入元素大于队尾元素,否则将队尾元素一一弹出,其次,当区间达到要求后,将队首元素取出(队首元素为上个区间最小值),如此循环直到达到输入整数末尾。递减队列与递增队列的不同之处在于被插元素要小于队尾元素。
#include <iostream>
#include<stdio.h>
using namespace std;
const int N = 1000008;
int min_[N], max_[N], index[N], a[N];
int n, k;
void Max()
{
int left = 1, right = 0;
for (int i = 1; i <= n; i++)
{
while (right >= left && a[index[right]] <= a[i]) right--;//维护单调递增队列
right++;//新队列元素总是安排在队尾
index[right] = i;//记录当前队列中对应元素的下标
if (index[right] - index[left] + 1 > k) left++;//去除原队首元素,进入新的队列
//i的有效位仅从k+1起
max_[i] = a[index[left]];
}
}
void Min()
{
int left = 1, right = 0;
for (int i = 1; i <= n; i++)
{
while (right >= left && a[index[right]] >= a[i]) right--;
index[++right] = i;
if (index[right] - index[left] + 1 > k) left++;
min_[i] = a[index[left]];
}
}
int main()
{
scanf("%d %d", &n, &k);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
Min();
Max();
for (int i = k; i <= n; i++) printf("%d ", min_[i]);
cout << endl;
for (int i = k; i <= n; i++) printf("%d ", max_[i]);
return 0;
}
cout << result << endl;
return 0;
}