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
解题过程与反思
这个题以前做过,但是没做出来,现在仍然错好多遍。。
一开始是写,用数组储存矩形高度,用一个空栈向里面逐渐加入矩形序号,如果遇到栈顶高度比它当前要加入的序号高度低的矩形就让其出栈并计算出栈矩形到当前点的面积更新最大面积,直到遇到比当前矩形低的矩形,将当前矩形入栈。等所有的矩形都被操作过后清空栈中剩余的矩形并且计算它们到结尾点的面积更新最大面积。结果改了三遍都wa…………觉得想象起来也没毛病啊,于时就百思不得其解遂放弃换了一种方法(正向反向两边遍历寻找每个高的左右端点,都是单调栈都差不多)过了。后来又觉得很纳闷就去看了讨论串,说是应该把所有的int改成long long,去改了一下发现过了,看来数据类型还是要多注意。
#include <iostream>
#include <cstdlib>
#include <stack>
#include <cmath>
#include <algorithm>
using namespace std;
long long a[100020];
int main(int argc, char** argv) {
long long n,temp;
while(1)
{cin>>n;
if(n==0)
break;
for(long long i=0;i<n;i++)
{ cin>>a[i];
}
a[n]=0;
//n++;
stack <long long> p;
p.push(-1);
long long maxx = 0,area=0;
for (long long i = 0; i < n; i++)
{
while (p.top() != -1 && a[p.top()] > a[i])
{ temp=p.top();
p.pop();
area=a[temp] * (i-1-p.top());
maxx = max(maxx ,area );
}
p.push(i);
}
while (p.top() != -1)
{ temp=p.top();
p.pop();
area=a[temp] * (n-1-p.top());
maxx = max(maxx ,area );
}
cout<<maxx<<endl;
}
return 0;
}
B - TT’s Magic Cat
题目大意
用数组a[i]表示n个城市中城市i的资产,现在给一个区间给区间内的所有城市加资产c,问经历q次操作后每个城市的资产。
样例
Input
4 2
-3 6 8 4
4 4 -2
3 3 1
Output
-3 6 9 2
解题过程与反思
已经提前知道是差分于是就套了公式,需要用差分的应该是对大区间进行区间加的情况。差分数组储存的是数组的差,原数组是差分数组的前缀和,如果修改区间内所有数的值需要遍历该区间会超时,如果是差分数组就只需要对区间端点进行处理,对区间[l,r]全部加c只需要对两个值进行修改,b[l]=b[l]+c, b[r+1]=b[r+1]-c.输出时输出差分数组前缀和就是原数组了。在查资料的时候发现居然有二维前缀和,而且还也能用差分(菜到放眼一望全是不知道)
#include <iostream>
#include <cstdlib>
#include <stack>
#include <cmath>
#include <algorithm>
using namespace std;
long long a[200200];
long long b[200200];
int main(int argc, char** argv) {
int n,q,temp;
cin>>n>>q;
for(long long i=1;i<=n;i++)
{cin>>a[i];
if(i==1)
b[i]=a[i];
else
b[i]=a[i]-a[i-1];
}
long long l,r,c;
for(long long i=0;i<q;i++)
{ scanf("%lld %lld %lld",&l,&r,&c);
b[r+1]=b[r+1]-c;
b[l]=b[l]+c;
}
long long m=0;
for(long long i=1;i<=n;i++)
{ m=m+b[i];
cout<<m<<" ";
}
return 0;
}
C - 平衡字符串
解题过程与反思
还是要确定一个区间的问题吗,每个字母的出现次数要是字符串总长度的四分之一,就先确定各个字母的出现次数如果符合就输出0,不符合就进行判断。从字符串的零下标开始假设有个框它有左端点和右端点一开始都是0,先向前移动右端点被框住的字符是预定修改的字符所以字母数量去除1,检查四个字母数量,如果都比平均数小说明框多了,左端点前进1把左侧的字母放出来,更新框长度(保留最小框),直到有一个字母数大于平均数重新开始移动右端点,右端点到达末端时结束输出框长度。
#include <iostream>
#include <cstdlib>
#include <stack>
#include <cmath>
#include <algorithm>
#include <string>
using namespace std;
int a[4]={0};
int chang (char p)
{ if(p== 'Q')
return 0;
if (p== 'W')
return 1;
if (p== 'E')
return 2;
if (p== 'R')
return 3;
}
int main(int argc, char** argv) {
int n ,ans=0;
string s;
cin>>s;
n=s.length()/4;
for(int i=0;i<s.length();i++)
{
a[chang(s[i])]++;
}
if(a[0]==n&&a[1]==n&&a[2]==n&&a[3]==n)
cout<<"0";
else
{int l=0,r=0,len=s.length();
ans=len;
while(r<len)
{ a[chang(s[r])]--;
int f=0;
for(int i=0;i<4;i++)
{if(a[i]>n)
{
f=1;
break;
}
}
while(f==0&&l<len)
{a[chang(s[l])]++;
ans=min(ans,r-l+1);
if(a[chang(s[l])]>n)
{
f=1;
}
l++;
}
r++;
}
cout<<ans;
}
return 0;
}
D - 滑动窗口滑动窗口
解题过程
滑动窗口单调队列。单调队列是一种能在队列两端进行删除操作,保持单调性的一种队列。求最小值应该维护一个递减的队列,最大值就应该维护一个递增的队列,每次取出队首元素就是答案。首先第一个元素进队尾,开始插入后续元素保持队列里的元素数量不大于k并且窗口不出界,每次给新元素找位置,被删除的都是比新元素大或小的而且先进入窗口肯定先于新元素出窗口都是不会成为队首的数,当队首元素出窗口时删除队首元素。储存每一次前进时的队首元素最后作为答案输出。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
using namespace std;
int a[1000200];
int maxx[1000200];
int minn[1000200];
int q[1000200] ;
int main(int argc, char** argv) {
int n,k,l,r;
cin>>n>>k;
for(int i=1;i<=n;i++)
{scanf("%d",&a[i]);
}
memset(q,sizeof(q),0);
int beg=1,end=1;
q[end]=1;
minn[1]=a[1];
for (int i=2;i<=n;i++)
{
while ((beg<=end)&&(a[i]<a[q[end]]))
end--;
q[end+1]=i;
end++;
if((beg<=end)&&(q[beg]<i+1-k))
beg++;
minn[i]=a[q[beg]];
}
memset(q,sizeof(q),0);
beg=1;end=1;
q[end]=1;
maxx[1]=a[1];
for (int i=2;i<=n;i++)
{
while ((beg<=end)&&(a[i]>a[q[end]]))
end--;
q[end+1]=i;
end++;
if((beg<=end)&&(q[beg]<i+1-k))
beg++;
maxx[i]=a[q[beg]];
}
for(int i=k;i<=n;i++)
{
cout<<minn[i];
if(i!=n)
cout<<" ";
}
cout<<endl;
for(int i=k;i<=n;i++)
{
cout<<maxx[i];
if(i!=n)
cout<<" ";
}
return 0;
}