P4484 [BJWC2018] 最长上升子序列
思路
看到排列和 LIS,所以想到了杨表。
设杨图单元格数为 \(n\),则其每一行的格数构成了 \(n\) 的一种整数划分。
向一个单元格数为 \(n\),划分为 \(\lambda\) 的杨图 \(Y_{\lambda}\) 中,插入 \(1\sim n\) 的排列,我们有钩长公式,得到的标准杨表的数量 \(d_{\lambda}\) 为:
\[d_{\lambda} = \frac{n!}{\prod_{(i,j)\in Y_{\lambda}} h_{\lambda}(i,j)}
\]
此时对应排列的 LIS 长度,为杨表第一行的长度 \(|S_{\lambda}|\)。
对于划分都为 \(\lambda\) 的杨表,我们有 Robinson-Schensted correspondence 定理,它们中两两会唯一对应一种排列。则 \(|S_{\lambda}|\) 对答案的贡献为:
\[(d_{\lambda})^2|S_{\lambda}|
\]
我们钦定杨图的形态,则答案为:
\[\frac{1}{n!}\sum_{\lambda} (d_{\lambda})^2|S_{\lambda}|
\]
由于 \(n \le 28\),最多也就 \(3718\) 种划分,所以暴力枚举 \(\lambda\) 即可。
代码
inline void dfs(int las,int num){
if(num==n){
ll val = mul;
for(int i=1;i<=cnt;++i){
for(int j=1;j<=Y[i];++j){
int num = Y[i]-j+1,t = i+1;;
while(t<=cnt && Y[t]>=j) ++t,++num;
(val *= inv[num])%=mod;
}
}
(val *= val*Y[1]%mod)%=mod;
(ans += val)%=mod;
}
for(int i=1;i<=las;++i){
if(num+i>n) break;
Y[++cnt] = i;
dfs(i,num+i);
--cnt;
}
}
int main(){
read(n); mul = 1;
for(ll i=1;i<=n;++i) (mul *= i)%=mod;
for(int i=1;i<=n;++i){
Y[++cnt] = i;
dfs(i,i);
--cnt;
}
(ans *= quick_pow(mul,mod-2))%=mod;
printf("%lld",ans);
return 0;
}

浙公网安备 33010602011771号