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
做法
建立单调递减栈保存矩形高度。
比栈高(或栈为空)的直接压入,同时更新其对应宽度。
比其矮的,弹出栈,并计算每个矩形的高度用来存在ans里,
同时,更新其宽度。
全部弹出或找到比其矮的位置后,将新的更新完宽度的矩形压入。
注意 最后栈可能还有剩余,需要全部弹出(样例2)。
这里在输入的时候,直接多加了个a[n+1]=0;保证全部弹出
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int s[100009],a[100009],w[100009],p,n;
long long ans;
int main()
{
while(~scanf("%d",&n)&&n!=0)
{ans=0;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
a[n+1]=0;
p=0;
for(int i=1;i<=n+1;i++)
{
if(a[i]>s[p])
{
s[++p]=a[i];
w[p]=1;
}
else
{
int wid=0;
while(s[p]>a[i])
{
wid+=w[p];
ans=max(ans,(long long )wid*s[p]);
p--;
}
s[++p]=a[i],w[p]=wid+1;
}
}
printf("%lld\n",ans);
}
}
B
题意
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
做法
差分数组,单点操作代替区间操作。
注意点:1、数组开成long long
2、r是否等于右边界特判
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
long long a[1000009],b[1000009],q,n,l,r,temp;
int main()
{ios::sync_with_stdio(false);
cin>>n>>q;
for(int i=1;i<=n;i++)cin>>a[i];
b[1]=a[1];
for(int i=2;i<=n;i++)b[i]=a[i]-a[i-1];
//for(int i=1;i<=n;i++)cout<<b[i]<<"&";
for(int i=1;i<=q;i++)
{
cin>>l>>r>>temp;
b[l]+=temp;
if(r!=n)b[r+1]-=temp;
}
a[1]=b[1];
cout<<a[1]<<" ";
for(int i=2;i<=n;i++)
{
a[i]=b[i]+a[i-1];
cout<<a[i]<<" ";
}
}
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’.
做法
特殊判断,四个字母个数已经相等,直接输出答案。
否则,利用尺取法。
取去掉l-r的区间的四个字母个数的最大值,然后查看每个字母需要补几个。
总和小于r-l+1或者大于但差距不是4的整数倍时,说明l-r区间不满足,需要更新
若大于,且差距为4的整数倍,说明满足,记录区间长度。
代码
#include<iostream>
#include<cstring>
using namespace std;
string s;
int l,r,ans=99999999;
int sum[4],temp[4];
int main()
{
cin>>s;
for(int i=0;i<s.length();i++)
{
if(s[i]=='Q')sum[0]++;
if(s[i]=='W')sum[1]++;
if(s[i]=='E')sum[2]++;
if(s[i]=='R')sum[3]++;
}
if(sum[0]==sum[1]&&sum[0]==sum[2]&&sum[0]==sum[3])
{
cout<<0<<endl;
return 0;
}
while(r<s.length())
{memset(temp,0,sizeof(temp));
for(int i=l;i<=r;i++)
{
if(s[i]=='Q')temp[0]++;
if(s[i]=='W')temp[1]++;
if(s[i]=='E')temp[2]++;
if(s[i]=='R')temp[3]++;
}
int maxx=0;
for(int i=0;i<4;i++)
{
if(sum[i]-temp[i]>maxx)maxx=sum[i]-temp[i];
}
int bj=r-l+1;
for(int i=0;i<4;i++)
{
bj-=(maxx-sum[i]+temp[i]);
}
if(bj>=0&&bj%4==0)
{
ans=min(ans,r-l+1);
if(l==r)
{
l++;
r++;
}
else l++;
}
else
{
r++;
}
}
cout<<ans;
}
总结
D
题意
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<cstring>
using namespace std;
int n,k,q1[1000009],q2[1000009],a[1000009],amin[1000009],amax[1000009],l=1,r=1;
int main()
{ ios::sync_with_stdio(false);
cin>>n>>k;
for(int i=1;i<=n;i++)cin>>a[i];
q1[1]=1;
for(int i=1;i<=n;i++)
{// cout<<q1[l]<<" "<<q1[r]<<" "<<a[q1[l]]<<endl;
while(l<=r&&q1[l]<=i-k)l++;
while(l<=r&&a[q1[r]]>=a[i])r--;
q1[++r]=i;
amin[i]=a[q1[l]];
}
for(int i=k;i<=n;i++)
{
cout<<amin[i]<<" ";
}
cout<<endl;
q2[1]=1;
l=1;
r=1;
for(int i=1;i<=n;i++)
{ //cout<<q2[l]<<" "<<q2[r]<<" "<<a[q2[l]]<<endl;
while(l<=r&&q2[l]<=i-k)l++;
while(l<=r&&a[q2[r]]<=a[i])r--;
q2[++r]=i;
amax[i]=a[q2[l]];
}
for(int i=k;i<=n;i++)
{
cout<<amax[i]<<" ";
}
}
总结
不关同步超时!!