Bad Hair Day [POJ3250] [单调栈 或 二分+RMQ]
题意
Farmer John的奶牛在风中凌乱了它们的发型……
每只奶牛都有一个身高hi(1 ≤ hi ≤ 1,000,000,000),现在在这里有一排全部面向右方的奶牛,一共有N只(1 ≤ N ≤ 80,000)。对于奶牛i来说,如果奶牛i+1,i+2,……,N这些奶牛的身高严格小于奶牛i,则奶牛i可以看到它们凌乱的发型。
输入
第一行 奶牛数量N
第二到 N+1行:第i+1行输入奶牛i的身高
输出
第一行:一个整数即c1到cN的和
样例输入
6
10
3
7
4
12
2
样例输出
5
分析
方法一
对于i,我们知道,令j∈[i+1,n],s=max(hi+1....hj)是具有单调性的(感性理解,j越大数字越多,同时j更小时的数也没有丢掉),所以如果s<=h[i]时,就可以继续向右扩张。使用二分查找,RMQ查询。RMQ可以使用ST达到O(1)的查询。
方法二
一头牛看到多少牛不好做,但可以被多少牛看到可解。只要在左边形成一个递减的数列,且最后一个大于当前的牛即可,数列大小即为当前牛的答案。可以用单调栈维护。
代码(法一)
1 #include<set> 2 #include<map> 3 #include<queue> 4 #include<stack> 5 #include<cmath> 6 #include<cstdio> 7 #include<cstring> 8 #include<iostream> 9 #include<algorithm> 10 #define RG register ll 11 #define rep(i,a,b) for(RG i=a;i<=b;++i) 12 #define per(i,a,b) for(RG i=a;i>=b;--i) 13 #define ll unsigned long long 14 #define inf (1<<29) 15 #define maxn 80005 16 #define ls (pos<<1) 17 #define rs (pos<<1|1) 18 #define mid ((t[pos].l+t[pos].r)>>1) 19 using namespace std; 20 ll n,ANS; 21 ll num[maxn],mx[maxn][18]; 22 inline ll read() 23 { 24 ll x=0,f=1;char c=getchar(); 25 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 26 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} 27 return x*f; 28 } 29 /* 30 void build(ll pos,ll l,ll r) 31 { 32 t[pos].l=l,t[pos].r=r; 33 if(l==r) {t[pos].mx=num[l];return;} 34 build(ls,l,mid);build(rs,mid+1,r); 35 t[pos].mx=max(t[ls].mx,t[rs].mx); 36 } 37 38 ll query(ll pos,ll l,ll r) 39 { 40 if(l<=t[pos].l&&t[pos].r<=r) return t[pos].mx; 41 ll ans=0; 42 if(l<=mid) ans=query(ls,l,r); 43 if(r>mid) ans=max(ans,query(rs,l,r)); 44 return ans; 45 } 46 */ 47 48 void ST() 49 { 50 rep(i,1,n) mx[i][0]=num[i]; 51 rep(j,1,17) 52 rep(i,1,n) 53 if(i+(1<<j)-1<=n) 54 mx[i][j]=max(mx[i][j-1],mx[i+(1<<(j-1))][j-1]); 55 } 56 57 int query(int l,int r) 58 { 59 int len=log(r-l+1)/log(2); 60 return max(mx[l][len],mx[r-(1<<len)+1][len]); 61 } 62 63 int main() 64 { 65 n=read(); 66 rep(i,1,n) num[i]=read(); 67 //build(1,1,n); 68 ST(); 69 rep(i,1,n) 70 { 71 RG l=i+1,r=n,ans=i,md; 72 while(l<=r) 73 { 74 md=(l+r)>>1; 75 if(query(i+1,md)<num[i]) ans=md,l=md+1; 76 else r=md-1; 77 } 78 ANS+=ans-i; 79 } 80 cout<<ANS; 81 return 0; 82 }