题意
定义运算
定义两个等长的数组A、B
给定A数组,限制B数组的元素在0-1之间随机取值,如果B similar with A,B的权值定义为所有元素的和,否则为0.
问B的期望权值。
题解:
铁头娃上来就想用积分分治乱搞,结果被队友证明积分并不能救这个题。。
dls直播讲了这个题代码极其简单,那么我来复现顺便证明一下。。
下边的Bi表示任意一种随机生成的B数列,[Bi]=1代表Bi和A是Similar 否则[Bi]=0,类似艾佛森规约的写法,记|Bi|为Bi的个数
由于单点的概率=0,比如说生成[0.1,0.2,0.3]这种数列的概率为0,那么可以认为每一个元素不相等。
由于每一个Bi取值的独立性,因此Similar的Sum_Bi的期望也是n/2,因为生成任意一个B数列相当于排列问题,而生成Similar的B数列就是组合问题,意思是先生成n个数字,然后按照规定的顺序(即A数组决定的全序关系)排列即可。
推了这么半年。。最后要求Bi和A是Similar的概率。由于我们认为Bi的每个元素不相等。因此我们从小到大把Bi的元素重新标号成1..n,明显可以看出每种全排列是等可能的基本事件。。因此我们把一个连续的问题。。变成离散的了。。。然后就极其容易思考了。。。。
设Bj为一个n的全排列,A按照全序关系从小到大标号为1..n设为Ax排列
好的。。。问题现在变成了。。多少个n的全排列和Ax是Similar的。。。
因此,本题的解法刚刚开始。。。
首先观察最大的元素在A和B中的位置,显然要求他们位置相同。因为包含这个最大元素的区间的RMQ 相等。
然后考虑不包含这个最大元素的区间,显然这样的区间完全位于最大元素的左边/右边。进而我们看到了一个分治的模型:每次确定区间最大值。然后分治左右。
也就是dls说的A、B两个数组的笛卡尔树形态完全一样。
对于笛卡尔树上的某个点,显然我们要把这一段区间的最大值给这个点,然后我们把剩下的点分成两堆,分给左右子树。于是我们有一个递归的方案数计算公式:
F(x)表示给定|x|个元素,以x为根的整个子树的方案个数,左儿子记为L(x),右儿子记为R(x),树的大小记为|x|
好像就。。做完了。。
本题还有一个直觉上秒杀的方法。。证明不是特别的直觉,直接计算P([Bi]=1),设笛卡尔树的根为rt
考虑使用数学归纳法证明:
假设第一个公式中 F(x)=|x|!∏i∈x的子树1|i| F ( x ) = | x | ! ∏ i ∈ x 的 子 树 1 | i |
如果一个点的左右子树Size都小于等于1,结论显然成立。
假设一个点x左子树Size=n,右子树Size=m,
即|x|=n+m+1 ; |L(x)|=n ; |R(x)| = m 那么根据第一个公式
F(x)=C|L(x)||x|−1∗F(L(x))∗F(R(x))=Cnn+m∗F(L(x))∗F(R(x))=(m+n)!n!∗m!∗n!∏i∈L(x)子树|i|∗m!∏j∈R(x)子树|j|=(m+n)!∏i∈{R(x)子树,L(x)子树}|i|=(m+n+1)!|x|∗∏i∈{R(x)子树,L(x)子树}|i|=|x|!∏i∈x子树|i| F ( x ) = C | x | − 1 | L ( x ) | ∗ F ( L ( x ) ) ∗ F ( R ( x ) ) = C n + m n ∗ F ( L ( x ) ) ∗ F ( R ( x ) ) = ( m + n ) ! n ! ∗ m ! ∗ n ! ∏ i ∈ L ( x ) 子 树 | i | ∗ m ! ∏ j ∈ R ( x ) 子 树 | j | = ( m + n ) ! ∏ i ∈ { R ( x ) 子 树 , L ( x ) 子 树 } | i | = ( m + n + 1 ) ! | x | ∗ ∏ i ∈ { R ( x ) 子 树 , L ( x ) 子 树 } | i | = | x | ! ∏ i ∈ x 子 树 | i |归纳一波,假设成立
进而 F(rt)=n!∏i|i| F ( r t ) = n ! ∏ i | i |
于是 P([Bi]=1)=F(rt)n!=1∏i|i|=1∏iSizei P ( [ B i ] = 1 ) = F ( r t ) n ! = 1 ∏ i | i | = 1 ∏ i S i z e i
下面两份代码分别基于第一个和第二个公式。ps:数据太大,需要开栈。
//
// Created by calabash_boy on 18-7-24.
//他的名字是笛卡尔树。
//
#include<bits/stdc++.h>
using namespace std;
#define OPENSTACK
const int maxn = 1e6+100;
const int mod = 1e9+7;
typedef long long LL;
int stk[maxn],top;
int l[maxn],r[maxn],rt;
int n;
pair<int,int> a[maxn];
LL inv[maxn];
LL fac[maxn];
LL inv_fac[maxn];
int sz[maxn];
bool vis[maxn];
/* l 左儿子 r 右儿子 rt根*/
void build(){
top=0;
for (int i=1;i<=n;i++) l[i]=r[i]=vis[i] =0;
for (int i=1;i<=n;i++){
int k = top;
while (k&&a[i]<a[stk[k-1]])k--;
if (k) r[stk[k-1]] = i;
if (k<top) l[i] = stk[k];
stk[k++] =i;
top = k;
}
for (int i=1;i<=n;i++) vis[l[i]] = vis[r[i]] =1;
for (int i=1;i<=n;i++){
if (!vis[i]){
rt = i;
break;
}
}
}
LL power(LL x,LL y){
LL res =1;
while (y){
if (y&1)res = res*x%mod;
y>>=1;
x = x*x%mod;
}
return res;
}
inline LL C(int n,int m){
return fac[n]*inv_fac[m]%mod*inv_fac[n-m]%mod;
}
int dfs(int u){
sz[u]=1;
int ans =1;
if (l[u])ans=1LL*ans*dfs(l[u])%mod;
if (r[u])ans = 1LL*ans*dfs(r[u])%mod;
sz[u]+=sz[l[u]]+sz[r[u]];
return 1LL*ans*C(sz[u]-1,sz[l[u]])%mod;
}
void Main(){
inv[1]=fac[1]=fac[0]=1;
for (int i=2;i<maxn;i++)fac[i] = fac[i-1]*i%mod,inv[i] = inv[mod%i]*(mod-mod/i)%mod;
inv_fac[maxn-1] = power(fac[maxn-1],mod-2);
for (int i=maxn-2;i>=0;i--){
inv_fac[i] = inv_fac[i+1]*(i+1)%mod;
}
int T;
scanf("%d",&T);
while (T--) {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
int x;
scanf("%d", &x);
a[i] = {-x, i};
}
build();
printf("%d\n", inv[2] * n % mod * power(fac[n], mod - 2) % mod * dfs(rt) % mod);
}
}
int main(){
#ifdef OPENSTACK
int size = 70 << 20; // 256MB
char *p = (char*)malloc(size) + size;
#if (defined _WIN64) or (defined __unix)
__asm__("movq %0, %%rsp\n" :: "r"(p));
#else
__asm__("movl %0, %%esp\n" :: "r"(p));
#endif
#endif
Main();
#ifdef OPENSTACK
exit(0);
#else
return 0;
#endif
}
// H
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const ll mod=1000000007;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
// head
const int N=1010000;
int stk[N],top,l[N],r[N],vis[N],n,x,_;
PII a[N];
ll inv[N],ret;
int dfs(int u) {
int s=1;
if (l[u]) s+=dfs(l[u]);
if (r[u]) s+=dfs(r[u]);
ret=ret*inv[s]%mod;
return s;
}
void build() {
int top=0;
rep(i,1,n+1) l[i]=0,r[i]=0,vis[i]=0;
rep(i,1,n+1) {
int k=top;
while (k>0&&a[stk[k-1]]>a[i]) --k;
if (k) r[stk[k-1]]=i;
if (k<top) l[i]=stk[k];
stk[k++]=i;
top=k;
}
rep(i,1,n+1) vis[l[i]]=vis[r[i]]=1;
int rt=0;
rep(i,1,n+1) if (vis[i]==0) rt=i;
dfs(rt);
}
int main() {
inv[1]=1;
rep(i,2,1000001) inv[i]=inv[mod%i]*(mod-mod/i)%mod;
for (scanf("%d",&_);_;_--) {
scanf("%d",&n);
rep(i,1,n+1) {
scanf("%d",&x);
a[i]=mp(-x,i);
}
ret=inv[2]*n%mod;
build();
printf("%lld\n",ret);
}
}