一个有趣的期望问题:1~n随机排列前缀最大值集合元素个数的期望

解法

  • 元素x对答案如果产生了贡献,那么比x大的数字都在x的后面。
  • x成为天选之子,概率为1/(n-x+1)
  • 独立考虑每个元素对答案的贡献,所以答案为sigma 1/i,其中i: 1->n

Hiho1751

做法: Meow

Hiho1747

做法:

f(L,R)表示max(a[L~R])-min(a[L,R])

  • 逐个枚举左端点
  • 逐个枚举右端点

然后,我们发现逐个枚举右端点很辣鸡的。

我们用单调栈,维护在元素i后面的第一个大于a[i]的元素,与第一个小于a[i]的元素。

确定L,我们就可以把f(L,R)相等的R一起处理了。

复杂度O(NlogN),因为对1/x积分可知:1/1+1/2+...+1/n ~ log N

code

#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
const int N = 100000+10;
pair<int,int> stk[N]; int top;
int T, n, a[N], nex1[N], nex2[N];
long long cnt[N];
void brute() {
    long long sum[N]={0};

    for(int i=1;i<=n;i++){
        int mx=-1,mn=N;
        for(int j=i;j<=n;j++){
            mx=max(mx,a[j]); mn=min(mn,a[j]);
            sum[mx-mn]++;
            if(mx-mn==2) printf("[%d,%d]\n", i,j);
        }
    }
    for(int i=1;i<=n;i++){
        sum[i]+=sum[i-1];
    }
    for(int i=0;i<n;i++) {
        printf("%lld\n", sum[i]);
    }
}
int main() {
    scanf("%d",&T);
    while (T --){
        memset(cnt,0,sizeof(cnt));
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        //brute();
        top=0; stk[++top]=make_pair(N, n+1);
        for(int i=n;i>=1;i--) {
            while(a[i]>stk[top].first) top--;
            nex1[i]=stk[top].second;
            stk[++top]=make_pair(a[i],i);
        }

        top=0; stk[++top]=make_pair(0, n+1);
        for(int i=n;i>=1;i--) {
            while(a[i]<stk[top].first) top--;
            nex2[i]=stk[top].second;
            stk[++top]=make_pair(a[i],i);
        }

        vector<int> v;
        for(int i=1;i<=n;i++){
            v.clear();
     
            int now=i;
            while(1) {
                now=nex1[now]; 
                if(now==n+1) break;
                v.push_back(now);
            }
            now=i;
            while(1) {
                now=nex2[now];
                if(now==n+1) break;
                v.push_back(now);
            }
            v.push_back(n);
            sort(v.begin(),v.end());
            int mx=a[i],mn=a[i],pre=i;
            for(int j=0;j<v.size();j++){
                cnt[mx-mn]+=v[j]-pre;
                mx=max(mx,a[v[j]]), mn=min(mn,a[v[j]]);
                pre=v[j];
            }
            cnt[mx-mn]++;
        }
        for(int i=0;i<n;i++) {
            printf("%lld\n", cnt[i]);
            cnt[i+1]+=cnt[i];
        }
    }
}

posted @ 2018-06-05 01:23  RUSH_D_CAT  阅读(581)  评论(0编辑  收藏  举报