RMQ Similar SequenceTime Limit: 4000/2000 MS (Java/Others) Memory Limit: 255535/255535 K (Java/Others)Total Submission(s): 835 Accepted Submission(s): 255 Problem Description Chiaki has a sequence A={a1,a2,…,an} . Let RMQ(A,l,r) be the minimum i (l≤i≤r ) such that ai is the maximum value in al,al+1,…,ar . Input There are multiple test cases. The first line of input contains an integer T , indicating the number of test cases. For each test case: Output For each test case, output the answer as a value of a rational number modulo 109+7 . Sample Input 3 3 1 2 3 3 1 2 1 5 1 2 3 2 1 Sample Output 250000002 500000004 125000001 Source |
大致题意:给你一个串A,定义RMQ相似串为,对任意区间[L,R],两个串RMQ所在位置相同。告诉你B串中每个元素服从于[0,1]上相互独立的均匀分布。B的权值定义为,当B与A串RMQ相似时,权值为所有元素之和,否则为0。现在问你B串的期望权值是多少。
首先,看到这种RMQ然后两个串要相似的,很容易想到用笛卡尔树。所谓笛卡尔树,就是说,对于一个区间,我选择RMQ作为根,然后把区间分为两部分。这两部分再次分别用RMQ作为根继续划分,直到划分到单位区间。
这题的话求一个期望,显然只需要关心那些权值不为0的。B与A串RMQ相似,有一些条件,即每一个点是以它为根的子树中所有点对应数字中最大的一个。那么对于这个点来说,满足要求的概率就是1/size[i]。总的来说就是。然后再看权值和,由于每个元素相互独立,且服从于[0,1]上的均匀分布,所以显然权值和的期望就是,于是这题的答案就是具体在实现的时候,由于本题1e6的数据范围,直接递归求解回爆栈,所以要用手工栈模拟的方法。具体见代码:
#include<bits/stdc++.h>
#define mod 1000000007
#define LL long long
#define N 1000100
using namespace std;
struct PII
{
int first,second;
bool operator<(const PII &a) const
{
return first==a.first?second>a.second:first<a.first;
}
};
int T,stk1[N],stk2[N];
LL inv[N],ans;
PII a[22][N];
int v[N];
struct ST
{
void build(int n)
{
int t=31-__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))]);
}
}
}
PII getmax(int j,int k)
{
if (j==k) return a[0][j];
else
{
int t=31-__builtin_clz(k-j);
return max(a[t][j],a[t][k-(1<<t)+1]);
}
}
} seg;
void build(int l,int r)
{
int top=0;
stk1[++top]=l; stk2[top]=r; v[top]=0;
while(top)
{
l=stk1[top]; r=stk2[top]; v[top]++;
if (v[top]>2) {top--;continue;}
if (v[top]==2)
{
int x=seg.getmax(l,r).second;
if (x+1<r) stk1[++top]=x+1,stk2[top]=r,v[top]=0;
} else
{
ans=ans*inv[r-l+1]%mod;
int x=seg.getmax(l,r).second;
if (l<x-1) stk1[++top]=l,stk2[top]=x-1,v[top]=0;
}
}
}
void init()
{
inv[0]=inv[1]=1;
for(int i=2;i<N;i++)
inv[i]=(mod-mod/i)*inv[mod%i]%mod;
}
int main ()
{
init();
scanf("%d",&T);
while(T--)
{
int n; ans=1;
scanf("%d",&n);
for (int i = 1; i <= n; ++i)
{
scanf("%d",&a[0][i].first);
a[0][i].second=i;
}
seg.build(n);
build(1,n);
printf("%I64d\n",ans*inv[2]%mod*n%mod);
}
return 0;
}