【枚举+优化】【队列操作】【RMQ】奶牛派对 tahort.pas/c/cpp
奶牛排队 (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,现在正在尽力写,后面争取放上代码........
未完待续.....