zoukankan      html  css  js  c++  java
  • 一个有趣的期望问题: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]
    ", i,j);
            }
        }
        for(int i=1;i<=n;i++){
            sum[i]+=sum[i-1];
        }
        for(int i=0;i<n;i++) {
            printf("%lld
    ", 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
    ", cnt[i]);
                cnt[i+1]+=cnt[i];
            }
        }
    }
    
    
  • 相关阅读:
    <JavaScript> 组合继承
    <JavaScript> 稳妥构造函数模式与工厂模式的区别
    <JavaScript> call()、apply()、bind() 的用法
    <JavaScript>可枚举属性与不可枚举属性
    <JavaScript>闭包(closure)
    在MongoDB中实现聚合函数
    (转)如何入门 Python 爬虫
    Python爬虫实战四之抓取淘宝MM照片
    转载:十年驾车经验总结:活着,才是硬道理
    设计模式之单例模式的七种写法
  • 原文地址:https://www.cnblogs.com/RUSH-D-CAT/p/9136815.html
Copyright © 2011-2022 走看看