[ARC104] E - Random LIS
题面
题目描述
给定一个长度为 \(n\) 数组 \(A_i\),现对于 \(1\leq i\leq n\),等概率选取 \(B_i \in [1,A_i]\),求 \(B\) 的严格 LIS 期望长度,对 \(M=10^9+7\) 取模。
数据范围
-
\(1\leq n \leq 6\)。
-
\(1\leq A_i \leq 10^9\)。
题解
首先看到 \(n\) 很小,想到枚举每个元素排序后的排名 \(rk_i\),而后分别对每种情况计数和求 LIS。由于在本题中元素可以相等,所以级别是 \(O(n^n)\) 的而非 \(O(n!)\)。
然后对于相同的 \(rk_i\) 肯定取的是最小的上界,即 \(\displaystyle lim_i=\min_{rk_j=i} a_j\)。
记 \(\displaystyle m=\max_{i=1}^n rk_i\),则问题转化为:
求满足以下条件的长度为 \(m\) 的数组 \(c\) 的个数:
\(\forall 1\leq i\leq m\),有 \(c_i\in [1,lim_i]\)。
\(\forall 1\leq i\lt m\),有 \(c_i\lt c_{i+1}\)。
这是一个经典问题,首先将 \(lim\) 离散化,并将数轴按照 \(lim\) 分段,记构成第 \(i\) 段的集合为 \(v_i\)。
设 \(f_{i,j}\) 为已经考虑了前 \(i\) 个元素,并且 \(c_i \in v_j\) 内的方案数。
考虑枚举分段点 \(k\) 使得 \(\forall k\leq p\leq i\),都有 \(c_p\in v_j\),且 \(c_{k-1}\notin v_j\)。同时枚举 \(c_{k-1}\) 在哪一段内。
有转移式: \(\displaystyle f_{i,j}=\sum_{k\leq i} \binom{|v_j|}{i-k+1} \sum_{p\lt j} f_{k-1,p}\)。
二项式系数可以暴力计算,时间复杂度 \(O(n^{n+4}\log M)\)。
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
const int N=6+9;
const int mod=1e9+7;
const int inf=1e9+7;
inline void AddAs(int &x,int y){if((x+=y)>=mod) x-=mod;}
inline void SubAs(int &x,int y){if((x-=y)<0) x+=mod;}
inline void MulAs(int &x,int y){x=1ll*x*y%mod;}
inline int Add(int x,int y){if((x+=y)>=mod) x-=mod;return x;}
inline int Sub(int x,int y){if((x-=y)<0) x+=mod;return x;}
inline int Mul(int x,int y){return 1ll*x*y%mod;}
inline int QPow(int x,int y){
int res=1;
while(y){
if(y&1) MulAs(res,x);
MulAs(x,x);
y>>=1;
}
return res;
}
#define Inv(x) QPow(x,mod-2)
int rk[N],a[N],n;
inline bool Check(){
vector<int> vis(n+1,0);
vis[0]=1;
for(int i=1;i<=n;i++) vis[rk[i]]=1;
for(int i=1;i<=n;i++) if(vis[i]&&!vis[i-1]) return 0;
return 1;
}
int lim[N],f[N][N],m,ans;
inline int C(int n,int m){
if(m<0||n<m) return 0;
if(!m) return 1;
else return Mul(C(n-1,m-1),Mul(n,Inv(m)));
}
inline int LIS(){
vector<int> f(n+1);
f[0]=0;
int res=0;
for(int i=1;i<=n;i++){
for(int j=0;j<i;j++) if(rk[j]<rk[i]) f[i]=max(f[i],f[j]+1);
res=max(res,f[i]);
}
return res;
}
inline void Work(){
if(!Check()) return ;
m=0;
for(int i=1;i<=n;i++) m=max(m,rk[i]);
for(int i=1;i<=m;i++) lim[i]=inf;
for(int i=1;i<=n;i++) lim[rk[i]]=min(lim[rk[i]],a[i]);
vector<int> val({0});
for(int i=1;i<=m;i++) val.push_back(lim[i]);
sort(val.begin(),val.end());
val.erase(unique(val.begin(),val.end()),val.end());
int tot=val.size()-1;
for(int i=1;i<=m;i++) lim[i]=lower_bound(val.begin(),val.end(),lim[i])-val.begin();
memset(f,0,sizeof f);
f[0][0]=1;
for(int i=1;i<=m;i++){
for(int j=1;j<=tot;j++){
for(int k=1;k<=i;k++){
int tmp=C(val[j]-val[j-1],i-k+1);
bool flag=0;
for(int p=k;p<=i;p++) if(lim[p]<j) flag=1;
if(flag) continue ;
for(int p=0;p<j;p++) AddAs(f[i][j],Mul(f[k-1][p],tmp));
}
}
}
int tmp=0;
for(int i=1;i<=lim[m];i++) AddAs(tmp,f[m][i]);
AddAs(ans,Mul(tmp,LIS()));
}
inline void Solve(int i){
if(i>n) return Work();
for(int j=1;j<=n;j++){
rk[i]=j;
Solve(i+1);
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
Solve(1);
int mul=1;
for(int i=1;i<=n;i++) MulAs(mul,a[i]);
cout<<Mul(ans,Inv(mul))<<endl;
return 0;
}

浙公网安备 33010602011771号