https://www.cnblogs.com/henrici3106/p/16710990.html
1 到 N 的排列,最长上升子序列(LIS)长度的期望是多少? - 知乎
杨氏矩阵 - OI Wiki
感觉可能有用的就是一个Hook公式(勾长公式)吧
以及之前有类似的脑补过杨图,现在有了定义更好理解
以下图片,均来自于oiwiki
定义:整数划分中,表示一种具体的划分方案的图
比如对于10=5+4+1,(5,4,1)有如下杨图,英式递减,法式递增
英式:
法式:
对于n的一个整数拆分,满足,记作。
将长为n的排列填入杨图,满足每行每列元素单调递增的方案。
将数字填入杨图,满足每行单调不降、每列单调递增的方案。
一个格子 (s, t) 是边角当且仅当 (s + 1, t) 和 (s, t + 1) 都不存在格子。
1. 在当前行中找到最小的比 x 大的数 y。
2. 如果找到了,交换x和y,去下一行,用换下来的数继续执行操作1。
3. 如果找不到,就把 x 放在该行末尾并退出。此时记 x 在第 s 行第 t 列,则(s, t) 必定是一个边角。
1. 只删除边角(x,y),可以看做是插入操作的逆操作。
2. 删除一个处于第i行的x时,
①如果i=1,直接退出;
②否则,找到上一行最大的小于x的数y,交换x、y,并移步到上一行,继续考虑
n个方格的杨表填n的排列,使得每一列从上到下递减,每一行从左到右递减,求总方案数
定义每个方格的勾长=同行右边的方格数+同列下面的方格数+1
即:
对于排列 而言,设当前插入位置为 (x,y)
定义 P为 pi 顺序插入得到的杨表,
Q 为在 (x,y) 插入对应下标 i 得到的杨表,称为记录表,
并维持 Q 和 P 的形状相同。
例如:
一个 1 到 n 的排列 pi 与一对形状相同的标准杨表形成双射。
也就是说,设 为形状为 的填数方案,有: 成立
证明:
充分性:对于一个排列,有唯一对应的一对P、Q。
必要性:给定杨表P、Q,通过在P中不断删去Q中最大的元素(的最后一个元素),能唯一对应一个排列。
杨表的第一行就是序列的LIS/LDS(最长上升子序列/最长下降子序列)的长度,记为
求长为n(n<=28)的排列的最长上升子序列长度的期望
EI的讲解:题解 P4484 【[BJWC2018]最长上升子序列】 - Elegia - 洛谷博客
这题用状压dp不太好做,用杨表就是暴力枚举整数拆分+公式统计了
注意到拆分数的量级,所以,可以直接暴力枚举每个整数划分,
利用hook公式,求每个形状的杨表数量,
借助Robinson-Schensted correspondence帮助还原排列,
每个杨表的贡献是,统计答案
#include
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef pair P;
#define fi first
#define se second
#define dbg(x) cerr<<(#x)<<":"< dist(l, r); return dist(gen); }
const int N=30,mod=998244353;
int n,inv[N],a[N],ans;
void dfs(int x,int y){
if(!x){
int res=1;
rep(i,1,n){
res=1ll*res*i%mod;
}
rep(i,1,y-1){
rep(j,1,a[i]){
int ct=a[i]-j;
rep(k,i,y-1){
if(a[k]>=j)++ct;
}
res=1ll*res*inv[ct]%mod;
}
}
ans=(ans+1ll*res*res%mod*a[1]%mod)%mod;
}
rep(i,1,x){
if(y!=1 && i>a[y-1])continue;
a[y]=i;
dfs(x-i,y+1);
}
}
int main(){
sci(n);
inv[1]=1;
rep(i,2,n){
inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
}
dfs(n,1);
rep(i,1,n){
ans=1ll*ans*inv[i]%mod;
}
printf("%d\n",ans);
return 0;
}