【RQNOJ】460 諾諾的隊列
阿新 • • 發佈:2017-07-10
clas clu track 諾諾的隊列 span for struct string void
【題目大意】
求全部數對(i,j)滿足隨意a[k]<=a[i]且a[k]<=a[j]。
形象地說,就是有一群人站成一列。每一個人有一定的身高,然後問有多少對人能夠互相看得到。
把數對(i,j)簡單地稱之為看得到的數對。
【解析】單調棧
先借用一下曾經做的題:[Vijos]1926 紫色的手鏈。求隨意區間最大值異或次大值的最大值。
回想一下單調棧,就是存儲從高到低遞減的單調數據的棧。
求全部數對(i,j)滿足隨意a[k]<=a[i]且a[k]<=a[j]。
形象地說,就是有一群人站成一列。每一個人有一定的身高,然後問有多少對人能夠互相看得到。
把數對(i,j)簡單地稱之為看得到的數對。
【解析】單調棧
先借用一下曾經做的題:[Vijos]1926 紫色的手鏈。求隨意區間最大值異或次大值的最大值。
回想一下單調棧,就是存儲從高到低遞減的單調數據的棧。
借用曾經的做法,求出來的東西相對於全部看得到的數對,對於全部a[i]相等的看得見的數對,僅僅算了一次。
於是事實上每次高過別人的時候操作僅僅要加上s(a[i]),第一次比別人矮的時候加上1而不是s(a[i])。
把棧內的東西給擴充,不僅存元素。還存個數,這樣就攻克了。
單調棧代碼:
#include <cstdio> #include <cstring> #include <cstdlib> using namespace std; const int N=500001; struct Stack { int w,c; }stk[N]; int size; int n,w[N],cnt; inline int read(void) { int s=0,f=1; char c=getchar(); for (;c<'0'||c>'9';c=getchar()) if (c=='-') f=-1; for (;'0'<=c&&c<='9';c=getchar()) s=(s<<1)+(s<<3)+c-'0'; return s*f; } int main(void) { n=read(); for (int i=1;i<=n;i++) w[i]=read(); for (int i=1;i<=n;i++) { for (;size&&stk[size].w<w[i];size--) { cnt+=stk[size].c; stk[size].w=stk[size].c=0; } if (size&&stk[size].w==w[i]) { cnt+=stk[size].c; stk[size].c++; if (size-1) cnt++; } else { if (size) cnt++; stk[++size].w=w[i]; stk[size].c=1; } } printf("%d\n",cnt); return 0; }
【RQNOJ】460 諾諾的隊列