HDU 6305

题解:

先在【1,n】中找到最大的数的位置mid,建立左儿子【1,mid-1】,右儿子【mid+1,n】,然后在左右儿子中递归重复上述操作。

如数列:1 2 3 1 2 5 2 1,建图如下:

                                           

可知,第6个数(数字5)应该是8个数中最大的,概率为\frac{1}{8},第3个数(数字3)应该是前5个数中最大的,概率为\frac{1}{5},第2个数(数字2)应该是前2个数中最大的,概率为\frac{1}{2},以此类推。。。

最后,将所有的概率相乘,并乘以\frac{n}{2},就是最后的期望。

注意会爆栈,要用非递归的方法遍历。

代码:

#include<bits/stdc++.h>
#define N 1000010
#define INF 0x3f3f3f3f
#define LL long long
#define eps 1e-8
using namespace std;
const LL P=1e9+7;

int inv[N];int a[22][N],b[22][N];
LL ans;

inline int gm(int j,int k)
{
    if (j==0) return INF;
    int t=31-__builtin_clz(k-j);
    return a[t][j]>=a[t][k-(1<<t)+1]?b[t][j]:b[t][k-(1<<t)+1];
}

struct node
{
    int x,y;
}cc[N];

int main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    inv[1]=1;
    for (int i=2;i<=1000000;i++) inv[i]=inv[P%i]*(P-P/i)%P;
    int T;
    cin>>T;
    while (T--)
    {
        int n;
        cin>>n;
        for (int i=1;i<=n;i++)cin>>a[0][i],b[0][i]=i;
        int t=32-__builtin_clz(n);
        for (int j=1;j<=t;j++)
        {
            for (int i=1;i<=n;i++)if (i+(1<<(j-1)) <=n)
            {
                a[j][i]=max(a[j-1][i],a[j-1][i+(1<<(j-1))]);
                b[j][i]=a[j][i]==a[j-1][i]?b[j-1][i]:b[j-1][i+(1<<(j-1))];
            }
        }
        ans=(LL) n*inv[2]%P;
        int top=-1;
        cc[++top]=node{1,n};
        while( cc[top].x!=0 || top>0)
        {
            if (cc[top].x!=0)
            {
                ans=ans*inv[cc[top].y-cc[top].x+1]%P;
                int l=cc[top].x;int t=gm(cc[top].x,cc[top].y);
                if (cc[top].x<t-1)cc[++top]=node{l,t-1};else cc[++top].x=0;
            }else
            {
                top--;
                int t=gm(cc[top].x,cc[top].y);
                if (t<cc[top].y-1) cc[top]=node{t+1,cc[top].y};else
                cc[top].x=0;
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

非递归遍历二叉树:

猜你喜欢

转载自blog.csdn.net/nudt_spy/article/details/81191919
hdu
今日推荐