第一题
简单题意
给一个直方图,求直方图中的最大矩形的面积。多组数据,对于一组数据,只有一行,第一个为n,表示有n个整数,接下来是n个整数hi,n<=100 000,hi<=1000 000 000。n为0时表示结束。
思路
我们开一个栈,设其为单调递增,然后处理数据。
如果进入的数大于等于栈顶元素,入栈,并且记录入栈的位置,这样我们就知道以当前数字为矩形最左的边的位置,一个要注意的点就是入下列数据:2、1,当1进入栈时,2被弹出,此时栈中没有元素,那么我们就要将1的入栈位置记为1而不是2,因为如果以1为高度,第一个元素也可以取到1。
如果进入的数小于栈顶元素,栈顶元素弹出,并且计算弹出元素值*(i-入栈位置),结果若大于ans,存入ans。
此外还有一个地方就是不能直接使用int计算,因为hi<=1000 000 000,n<=100 000,所以要处理一下。
代码
#include<iostream>
using namespace std;
int main()
{
int n,x,l,tot,left,right,ans1,ans2,sum1,sum2;
int a[100010],b[100010];
cin>>n;
while (n!=0)
{
tot=1;
cin>>a[1];
b[1]=1;
ans1=0;
ans2=0;
for (int i=2;i<=n;i++)
{
cin>>x;
if (x>=a[tot])
{
tot++;
a[tot]=x;
if (tot!=1) b[tot]=i;
else b[tot]=1;
}
else
{
while (x<a[tot] && tot>0)
{
l=i-b[tot];
left=a[tot]/100000;
right=a[tot]%100000;
sum1=l*left;
sum2=l*right;
if (ans1<sum1 || (ans1==sum1 && ans2<sum2))
{
ans1=sum1;
ans2=sum2;
}
tot--;
}
tot++;
a[tot]=x;
}
}
while (tot>0)
{
l=n-b[tot]+1;
left=a[tot]/100000;
right=a[tot]%100000;
sum1=l*left;
sum2=l*right;
if (ans1<sum1 || (ans1==sum1 && ans2<sum2))
{
ans1=sum1;
ans2=sum2;
}
tot--;
}
ans1=ans1+ans2/100000;
ans2=ans2%100000;
if (ans1>0)
{
cout<<ans1;
if (ans2<10000) cout<<0;
if (ans2<1000) cout<<0;
if (ans2<100) cout<<0;
if (ans2<10) cout<<0;
cout<<ans2<<endl;
}
else
cout<<ans2<<endl;
cin>>n;
}
return 0;
}
第二题
简单题意
给出一个长度为n的数组,执行m次操作,操作输入格式为l,r,c,操作具体是将区间[l,r]内的数全部+c。
输入格式为第一行n,m,第二行为n个数,表示数组a,接下来m行,表示m个操作,每个操作为l,r,c。a[i]<=1 000 000,-100 000<=c<=100 000
输出为执行完m个操作之后的数组,每个数用空格隔开。
思路
差分,对于每个操作l,r,c,我们可以将其看为两个操作,l,n,c和r+1,n,-c,这样我们直接开一个数组b,b[i]表示a[i,n]要加b[i]。这样最终答案ans[i]就可以看做a[i]+b[1]+…+b[i],这样我们还可以优化一下,即ans[i]=ans[i-1]+b[i],若这样处理b数组初始就不能为0,而应该是b[i]=a[i]-a[i-1]。
数据要使用long long int存储计算。
代码
#include<iostream>
#include<cstdio>
using namespace std;
long long int a[300000];
long long int b[300000];
int main()
{
int m,n,l,r,c;
cin>>n>>m;
a[0] = 0;
for(int i=1;i<=n;i++)
{
scanf("%lld", &a[i]);
b[i]=a[i]-a[i-1];
}
for (int i=0;i<m;i++)
{
scanf("%d%d%d",&l,&r,&c);
b[l]=b[l]+c;
b[r+1]=b[r+1]-c;
}
a[0]=0;
for (int i=1;i<=n;i++)
{
a[i]=b[i]+a[i-1];
printf("%lld ",a[i]);
}
cout<<endl;
return 0;
}
第三题
简单题意
平衡字符串,给出一个字符串,字符串中只含有QWER这四个字符,要求修改连续的一段,是的QWER四个字符出现的次数相同。必然有解。
输入为一个字符串,输出为最小修改的长度。
思路
要让四个字符的出现次数相同,我们要将出现多的修改为出现少的。如平均5次,Q出现6次,W出现7次,E出现4次,R出现3次,那么我们要将1个Q和2个W改为1个E和2个R,所以在要修改的连续的子串中必须有1个Q和2个W。
我们可以维护l,r,求出[l,r]这个区间中各个字符出现的次数。若该子串满足替换要求,我们将r-l与ans比较,然后l++,看新的子串是否仍然合法,如合法继续更新答案并且l++,直至子串不合法。若子串不合法则r++,直至子串合法。
代码
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
string s;
cin>>s;
int a,b,c,d,l,r,x,y,z,w,ans;
a=0; b=0; c=0; d=0;
for (int i=0;i<s.length();i++)
{
if (s[i]=='Q') a++;
if (s[i]=='W') b++;
if (s[i]=='E') c++;
if (s[i]=='R') d++;
}
if (a==b && b==c && c==d)
{
cout<<0<<endl;
return 0;
}
x=a-s.length()/4;
y=b-s.length()/4;
z=c-s.length()/4;
w=d-s.length()/4;
a=0;b=0;c=0;d=0;
l=0; r=0;
ans=s.length();
bool o=true;
while (r<s.length())
{
if (s[r]=='Q') a++;
if (s[r]=='W') b++;
if (s[r]=='E') c++;
if (s[r]=='R') d++;
r++;
while (a>=x && b>=y && c>=z && d>=w && l<=r)
{
if (r-l<ans) ans=r-l;
if (s[l]=='Q') a--;
if (s[l]=='W') b--;
if (s[l]=='E') c--;
if (s[l]=='R') d--;
l++;
// cout<<a<<" "<<b<<" "<<c<<" "<<d<<endl;
// cout<<l<<" "<<r<<endl;
}
}
while (a>=x && b>=y && c>=z && d>=w && l<=r)
{
if (r-l<ans) ans=r-l;
if (s[l]=='Q') a--;
if (s[l]=='W') b--;
if (s[l]=='E') c--;
if (s[l]=='R') d--;
l++;
// cout<<a<<" "<<b<<" "<<c<<" "<<d<<endl;
// cout<<l<<" "<<r<<endl;
}
cout<<ans<<endl;
return 0;
}
第四题
简单题意
滑动窗口,一个长度为n的数列和大小为k的窗口,窗口可以在数列上移动,要求给出窗口从左到右移动,每次窗口内的最大值和最小值。
输入格式为第一行n,k,第二行为长度为n的数列。
输出格式为两行,第一行为最小值,第二行为最大值。
思路
使用单调队列,我们使用i表示窗口的右端,即当前窗口位置为[i-k+1,i],i可以使用for循环。最小值我们维护一个单调递增队列,队首元素就是最小值,若当前加入元素比队尾元素小,根据单调队列的定义,那么就会出现一个山峰,如:1,4,3,但是这个4是不会成为最小值的,因为每个元素都要往前走,最后破坏队列,所以要删掉。
然后因为窗口的滑动,有些元素会过时被删掉,我们的i是使用for循环来移动的,所以元素过时是从队首开始过时,因为新加入的元素是加到队尾的。我们判断一下队首元素的编号q[head]与i-k的关系,如果q[head]<=i-k,说明元素已经过时,要弹出,head++。
最后当i>=w-1时,即窗口完全在数列中,我们就可以输出a[q[head]],这就是当前窗口的最小值。
最大值与最小值同理。
代码
#include<iostream>
#include<cstdio>
using namespace std;
int a[1000100],q[1000100];
int main()
{
int n,w,head,tail,ans,count;
cin>>n>>w;
for (int i=0;i<n;i++)
scanf("%d",&a[i]);
q[0]=0;
head=1; tail=0;
for(int i=0;i<n;i++)
{
if (head<=tail)
{
count=q[tail];
ans=a[count];
while (a[i]<ans && head<=tail)
{
tail--;
if (head<=tail)
{
count=q[tail];
ans=a[count];
}
}
}
tail++;
q[tail]=i;
while (q[head]<=i-w)
head++;
if(i>=w-1)
printf("%d ",a[q[head]]);
}
cout<<endl;
head=1; tail=0;
for(int i=0;i<n;i++)
{
if (head<=tail)
{
count=q[tail];
ans=a[count];
while (a[i]>ans && head<=tail)
{
tail--;
if (head<=tail)
{
count=q[tail];
ans=a[count];
}
}
}
tail++;
q[tail]=i;
while (q[head]<=i-w)
head++;
if(i>=w-1)
printf("%d ",a[q[head]]);
}
cout<<endl;
return 0;
}