A题:
题意:
对于一个序列A[1…N],一共N个数,除去M个数使剩下的数组成的整数最小。
也就是说在A[1…N]中顺次选取N-M个数,使值最小。
思路:
单调队列,删除少于要求各节点的话比之前的数字小,就一定把之前的删除,让小的这个做第一个,这样就相当于维护一个单挑队列,先满足前面的尽量小,能删多少删多少
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
char s[1010];
int n;
int st[1010];
int T;
int main()
{
while(~scanf("%s",s)){
int k = 0;
T = 0;
scanf("%d",&n);
st[0] = s[0]-'0';
for(int i = 1 ; i < strlen(s);i++){
while(T>=0&&s[i]-'0' < st[T] && k < n){
T--;
k++;
}
st[++T] = s[i]-'0';
}
int flag = false,ff = false;
for(int i = 0 ; i < strlen(s)-n ;i++){
if(st[i] != 0)
flag = true;
if(flag){
cout << st[i];
ff = true;
}
}
if(ff == false)
cout <<0;
cout << endl;
}
return 0;
}
B题:
题意:
给出一个数组,问你对于第i个数,从最后一个比它大的数到它之间比它小的数中最大的那个数的下标,以及它右边到第一个比它大的数中比它小的数中最大的那一个数的下标<下标从1开始>。
eg:5 2 4 3 1
l 0 0 2 0 0 对5来说左边比它小的数没有,所以是0。对2来说左边比它小的数没有,所以是0。对4来说左边比它小的数是2,所以下标是2。
r 3 0 4 5 0 对5来说右边比它小的数中最大的是4,是第3个,所以答案是3。对2来说右边比它小的数是1,但是4比2大,所以无法到达1,所以答案是0。对于4,右边比它小的数中最大一个3的下标是4,所以答案是4。
思路
单调队列。
先从左向右维护一个单调队列,然后在维护过程中最后一个从队列中剔除掉的即右边比它小的数中最大的那一个。
单调队列中的值是下标值。
从右向左再维护一个单调队列就可以求出另一个值。
#include<cstring>
#include<string>
#include<iostream>
#include<queue>
#include<cstdio>
using namespace std;
const int maxn = 50010;
int a[maxn];
int l[maxn];
int r[maxn];
int s[maxn];
int n,c;
void init()
{
scanf("%d",&n);
for(int i=1;i<=n;i++ )
scanf("%d",&a[i]);
memset(l,0,sizeof l);
memset(r,0,sizeof r);
}
void sov()
{
int top=-1;
a[0]=a[n+1]=(1<<30);
for(int i=1;i<=n+1;i++)
{
int flag=top;
while(top>=0&&a[i]>a[s[top]])
{
if(flag!=top) r[s[top]]=s[top+1];
top--;
}
s[++top]=i;
}
top=-1;
for(int i=n;i>=0;i--)
{
int flag=top;
while(top>=0&&a[i]>a[s[top]])
{
if(flag!=top) l[s[top]]=s[top+1];
top--;
}
s[++top]=i;
}
printf("Case %d:\n",c++);
for(int i=1;i<=n;i++)
{
printf("%d ",l[i]);
if(r[i]==n+1) printf("0\n");
else printf("%d\n",r[i]);
}
}
int main()
{
int T;
c=1;
scanf("%d",&T);
while(T--)
{
init();
sov();
}
return 0;
}
C题:
题意:
最大矩形的面积
思路:
每次都把当前的这个当成最大的,
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 100100;
long long a[maxn];
int n;
long long st[maxn];
void init()
{
for ( int i = 1 ; i <= n ; i ++ ) cin >>a[i] ;
}
void sov()
{
long long ans = 0;
memset(st,0,sizeof(st));
int k = 0;
for(int i = 1 ; i <= n+1;i++){
while(k>0 && a[i]<=a[st[k]]){
// st[k-1]+1~st[k]~i-1
cout<<"i = "<<i << " ans = "<<ans<<" k = "<<k<<" st[k] = "<<st[k] << " a[st[k]] = " <<a[st[k]] <<" (i-1 - st[k-1]) = " <<(i-1 - st[k-1])<<endl;
ans = max(ans, a[st[k]] * (i-1 - st[k-1])) ;
k--;
}
//cout << i <<" " <<a[i] << " " << st[k] <<"\n";
st[++k] = i;
}
cout <<ans<<endl;
}
int main()
{
while(1 == scanf("%d" , &n) && n) {
init();
a[0] = a[n+1] = 0;
sov();
}
return 0;
}