奶牛排队 (tahort)
Problem: tahort.pas/c/cpp
Input: tahort.in
Output: tahort.out
Memory Limit: 128 MB
Time Limit: 1 sec
【 问题描述】
奶牛在熊大妈的带领下排成了一条直队。
显然,不同的奶牛身高不一定相同……
现在,奶牛们想知道,如果找出一些连续的奶牛,要求最左边的奶牛A是最矮的,最右边的B是最高的,且B高于A奶牛,中间如果存在奶牛,则身高不能和A、B奶牛相同。问这样的奶牛最多会有多少头?
从左到右给出奶牛的身高,请告诉它们符合条件的最多的奶牛数(答案可能是0,2,但不会是1)。
【输入】
第一行一个数N (2≤N≤l00000),表示奶牛的头数。
接下来N个数,每行一个数,从上到下表示从左到右奶牛的身高(1≤身高≤ maxlongint)。
【输出】
第一行,表示最多奶牛数。
【样例】
Tahort.in
5
1
2
3
4
1
Tahort.out
4
【样例解析】
取第1头到第4头奶牛,满足条件且为最多。
先说说最朴素的方法,谁都可以想得到,枚举左界 i ,枚举右界 j ,在从 i -> j 用 k 来枚举判断,当然这是接近O(N3)的算法了,就这题的数据O(N2)都过不了,更别说O(N3)了。。。当然朴素可以拿来对拍,然后可以放心大胆去优化,可以保证正确性
那O(N3)的算法就只能对拍的了吗?我们也可以优化!既然左界是最小的,那么后面的就不可能比它更小或相等,所以我们只需要在枚举 j 那里加一句,判断是否 j 那里的数比 i 那里的数还小或者相等,如果成立,那显然后面就没必要再找下去了,所以马上break,就只需要加这一句话,就能从过3组变成过9组!!!我上午以为这个优化不大,所以就又写了队列优化,维护首尾指针,结果没有优化到位,还是也只过了9组。。。。。
后来看数据,第9组有点坑。。。是锯齿状(100000,1,99999,2,99998,3,99997,4,......)
所以我们可以改成倒序枚举就可以全过了。
这里先给出 O(N3)枚举+优化 的代码
/*
C++ Code 枚举+优化
http://oijzh.cnblogs.com
By jiangzh
*/
#include<cstdio>
#define MAXN 100010
#define max(a,b) ((a)>(b)?(a):(b))
int n,a[MAXN];
int ans=0;
void init()
{
freopen("Tahort.in","r",stdin);
freopen("Tahort.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
}
void work()
{
bool flag;
for(int i=n;i>1;i--)
{
for(int j=i-1;j>=1;j--)
{
if(a[i]<=a[j])break;//需要满足 a[i]<a[j]
flag=true;
for(int k=j+1;k<i;k++)
if(a[k]<=a[j] || a[k]>=a[i]) {flag=false;break;}//需要满足 a[k]>a[i] a[k]<a[j]
if(flag) ans=max(ans,i-j+1);
if(ans==n) {printf("%d",ans);return;}
}
}
printf("%d",ans);
}
int main()
{
init();
work();
return 0;
}
至于我上午写的队列优化,是我上午历经与朴素程序N+次对拍才改出来的,不过也只能优化到90分,后面也没优化到100分,过程也不好解释,下面给出代码,尽力看吧
/*
C++ Code
http://oijzh.cnblogs.com
By jiangzh
队列维护
*/
#include<cstdio>
#define MAXN 100010
#define max(a,b) ((a)>(b)?(a):(b))
int n,a[MAXN];
int ans=0;
void init()
{
freopen("Tahort.in","r",stdin);
freopen("Tahort.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
}
void work()
{
int head=1,tail=0,maxnow=0;
while(tail<n)
{
tail++;//尾指针+1
if(maxnow<a[tail]) maxnow=a[tail];//更新当前最大值
else{
int k=tail;
while(k<n && a[k]<=maxnow)
{
if(a[k]<=a[head]) {k=0;break;}
k++;
}
if(a[k]>maxnow) {tail=k;maxnow=a[k];}
else {head=tail;maxnow=a[head];}
}
if(head<tail) ans=max(ans,tail-head+1);
if(n-head+1<=ans) break;
}
printf("%d",ans);
}
int main()
{
init();
work();
return 0;
}
这一题的标准算法是RMQ,现在正在尽力写,后面争取放上代码........
未完待续.....