题目大意
给出一个随机的排列,请你计算最大值减最小值的差小于等于0~$n$-1的区间分别有多少个。
题目分析
此题可做完全基于随机性。
这题似乎有分治的解法。
然而我用的单调栈+双指针。
我们先预处理出$i$后比$i$大/小的第一个数的位置,可以使用单调栈维护。
然后我们枚举区间起点,维护一个最大值,一个最小值,找到最大值、最小值最早变化的地方,那么在变化的地方前,最大值最小值之差一定,我们可以$O(1)$更新。
这个做法最坏$O(n^2)$,但因为数据随机,所以可以过。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| #include<algorithm> #include<iostream> #include<iomanip> #include<cstring> #include<cstdlib> #include<vector> #include<cstdio> #include<cmath> #include<queue> #include<stack> using namespace std; typedef long long LL; inline const LL Get_Int() { LL num=0,bj=1; char x=getchar(); while(x<'0'||x>'9') { if(x=='-')bj=-1; x=getchar(); } while(x>='0'&&x<='9') { num=num*10+x-'0'; x=getchar(); } return num*bj; } const int maxn=100005; LL n,a[maxn],NextMax[maxn],NextMin[maxn],Ans[maxn],pos[maxn]; int main() { n=Get_Int(); for(int i=1; i<=n; i++)a[i]=Get_Int(),pos[a[i]]=i,NextMax[i]=NextMin[i]=n+1; stack<int>S; for(int i=1; i<=n; i++) { while(!S.empty()&&a[S.top()]>a[i]) { NextMin[S.top()]=i; S.pop(); } S.push(i); } S=stack<int>(); for(int i=1; i<=n; i++) { while(!S.empty()&&a[S.top()]<a[i]) { NextMax[S.top()]=i; S.pop(); } S.push(i); } for(int i=1; i<=n; i++) { int Max=a[i],Min=a[i],j=i; while(j<=n) { if(NextMin[pos[Max]]<NextMax[pos[Min]]) { Ans[Max-Min]+=NextMin[pos[Max]]-j; j=NextMin[pos[Max]]; Max=a[NextMin[pos[Max]]]; } else { Ans[Max-Min]+=NextMax[pos[Min]]-j; j=NextMax[pos[Min]]; Min=a[NextMax[pos[Min]]]; } } } for(int i=1; i<=n; i++)Ans[i]+=Ans[i-1],printf("%lld\n",Ans[i-1]); return 0; }
|