HDU 6305
题解:
首先B数列一定是一个下标满足二叉搜索树,值满足大根堆的东西。
先考虑B数列满足这个条件的概率。
首先根的元素一定是A数列中最大的(第二关键字是下标最小),考虑B数列中对应的元素。 这个元素是最大的概率是
1n
1
n
, 递归的求解左右两个区间满足条件的概率乘起来就是B数列满足条件的概率。
最后在将概率和B数列的和的期望即
n2
n
2
乘起来就行了。
对于求解区间最大值的位置可以使用线段树维护。
时间复杂度:
O(nlogn)
O
(
n
l
o
g
n
)
代码:
#include<bits/stdc++.h>
#define LL long long
#define ull unsigned long long
#define ULL ull
#define mp make_pair
#define pii pair<int,int>
#define piii pair<int, pii >
#define pll pair <ll,ll>
#define pb push_back
#define big 20160116
#define INF 2147483647
#define pq priority_queue
#define rank rk124232
#define y1 y20160116
#define y0 y20160110
using namespace std;
inline int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
namespace Mymath{
LL qp(LL x,LL p,LL mod){
LL ans=1;
while (p){
if (p&1) ans=ans*x%mod;
x=x*x%mod;
p>>=1;
}
return ans;
}
LL inv(LL x,LL mod){
return qp(x,mod-2,mod);
}
LL C(LL N,LL K,LL fact[],LL mod){
return fact[N]*inv(fact[K],mod)%mod*inv(fact[N-K],mod)%mod;
}
template <typename Tp> Tp gcd(Tp A,Tp B){
if (B==0) return A;
return gcd(B,A%B);
}
template <typename Tp> Tp lcm(Tp A,Tp B){
return A*B/gcd(A,B);
}
};
namespace fwt{
using namespace Mymath;
void FWT(int a[],int n,LL mod)
{
for(int d=1;d<n;d<<=1)
for(int m=d<<1,i=0;i<n;i+=m)
for(int j=0;j<d;j++)
{
int x=a[i+j],y=a[i+j+d];
a[i+j]=(x+y)%mod,a[i+j+d]=(x-y+mod)%mod;
//xor:a[i+j]=x+y,a[i+j+d]=x-y;
//and:a[i+j]=x+y;
//or:a[i+j+d]=x+y;
}
}
void UFWT(int a[],int n,LL mod)
{
LL rev=inv(2,mod);
for(int d=1;d<n;d<<=1)
for(int m=d<<1,i=0;i<n;i+=m)
for(int j=0;j<d;j++)
{
int x=a[i+j],y=a[i+j+d];
a[i+j]=1LL*(x+y)*rev%mod,a[i+j+d]=(1LL*(x-y)*rev%mod+mod)%mod;
//xor:a[i+j]=(x+y)/2,a[i+j+d]=(x-y)/2;
//and:a[i+j]=x-y;
//or:a[i+j+d]=y-x;
}
}
void solve(int a[],int b[],int n,LL mod)
{
FWT(a,n,mod);
FWT(b,n,mod);
for(int i=0;i<n;i++) a[i]=1LL*a[i]*b[i]%mod;
UFWT(a,n,mod);
}
};
const int Maxn=1e6+5;
int n,a[Maxn];
int tree[Maxn*4],id[Maxn*4];
void build(int p,int l,int r){
if (l==r){
tree[p]=a[l];
id[p]=l;
return;
}
int mid=l+r>>1;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
tree[p]=max(tree[p*2],tree[p*2+1]);
if (tree[p*2]==tree[p]){
id[p]=id[p*2];
}
else{
id[p]=id[p*2+1];
}
}
pair<int,int> query(int p,int l,int r,int lo,int hi){
if (lo<=l && r<=hi){
return mp(tree[p],id[p]);
}
int mid=l+r>>1;
if (lo<=mid && hi>mid){
pair<int,int> lf=query(p*2,l,mid,lo,min(hi,mid));
pair<int,int> rg=query(p*2+1,mid+1,r,max(lo,mid+1),hi);
if (lf.first>=rg.first){
return lf;
}
return rg;
}
if (lo<=mid){
return query(p*2,l,mid,lo,min(hi,mid));
}
if (hi>mid){
return query(p*2+1,mid+1,r,max(lo,mid+1),hi);
}
}
LL ans;
using namespace Mymath;
const LL mod=1e9+7;
void solve(int l,int r){
if (l>=r) return;
pair<int,int> x=query(1,1,n,l,r);
ans=ans*inv(r-l+1,mod)%mod;
solve(l,x.second-1);
solve(x.second+1,r);
}
void mian(){
n=read();
for (int i=1;i<=n;i++) a[i]=read();
ans=(LL)n*inv(2,mod)%mod;
build(1,1,n);
solve(1,n);
printf("%I64d\n",ans);
}
int main(){
int t;
t=read();
while (t--){
mian();
}
return 0;
}