把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【洛谷4484】[BJWC2018] 最长上升子序列(杨表)

点此看题面

  • 求一个长度为\(n\)的随机排列的最长上升子序列长度期望。
  • \(n\le28\)

杨表与钩子定理

关于杨表的一些基础知识可见这篇博客:杨表的构造与基本性质

着重需要了解一个性质,就是一张杨表及其记录表与排列一一对应,即两张形状相同的杨表与排列一一对应

这里再介绍一下杨表的钩子定理。

定义一张形状为\(\lambda\)的杨表中一个格子\((i,j)\)的钩子函数\(h_{\lambda}(i,j)\)为它所在行右方格子数+它所在列下方格子数+它自身(因为长得像一个钩子,所以叫做钩子函数)。

钩子定理为我们指出,一张形状为\(\lambda\vdash n\)的杨表数目,就是\(\frac{n!}{\prod h_{\lambda}(i,j)}\)

暴枚杨表形状

对于这道题,我们首先暴枚杨表的形状,这一部分时间复杂度是\(O(p(n))\)的(\(p(n)\)表示\(n\)的拆分个数,显然小于\(2^n\))。

枚举出形状\(\lambda\)之后,杨表第一行的长度\(\lambda_1\)就是最长上升子序列长度,而这种形状的杨表个\(f_{\lambda}\)数可以直接钩子定理\(O(n)\)计算。由于两张形状相同的杨表对应一个排列数,因此答案就是:

\[\frac1{n!}\sum_{\lambda\vdash n}f_{\lambda}^2\times\lambda_1 \]

比需要本地打表才能过掉的状压\(DP\)不知道高明到哪去了。

代码:\(O(np(n))\)

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 28
#define X 998244353
using namespace std;
int n,Fac,IFac,a[N+5],b[N+5],Inv[N+5];
I int Calc(CI c) {RI i,j,t=Fac;for(i=1;i<=c;++i) for(j=1;j<=a[i];++j) t=1LL*t*Inv[a[i]-j+b[j]-i+1]%X;return t;}//钩子定理计算杨表个数
int ans;I void dfs(CI c,CI x,CI lim)//暴枚杨表形状
{
	if(!x) {RI t=Calc(c-1);ans=(ans+1LL*t*t%X*a[1])%X;return;}//统计答案,∑f^2×λ1
	RI i;for(i=1;i<=min(lim,x);++i) ++b[a[c]=i],dfs(c+1,x-i,i);W(--i) --b[i];//划分,不能超过上行长度
}
int main()
{
	RI i;for(scanf("%d",&n),Inv[1]=Fac=IFac=1,i=2;i<=n;++i)
		Inv[i]=1LL*(X-X/i)*Inv[X%i]%X,Fac=1LL*Fac*i%X,IFac=1LL*IFac*Inv[i]%X;
	return dfs(1,n,n),printf("%d\n",1LL*ans*IFac%X),0;//除以总方案数计算期望
}
posted @ 2021-05-17 16:40  TheLostWeak  阅读(211)  评论(0编辑  收藏  举报