https://www.cnblogs.com/henrici3106/p/16710990.html
1 到 N 的排列,最长上升子序列(LIS)长度的期望是多少? - 知乎
感觉可能有用的就是一个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中最大的元素(的最后一个元素),能唯一对应一个排列。
记n的拆分数为p(n),则下式可以估算其量级:
杨表的第一行就是序列的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<int,int> P;
- #define fi first
- #define se second
- #define dbg(x) cerr<<(#x)<<":"<
" " ; - #define dbg2(x) cerr<<(#x)<<":"<
- #define SZ(a) (int)(a.size())
- #define sci(a) scanf("%d",&(a))
- #define pb push_back
- #define pt(a) printf("%d",a);
- #define pte(a) printf("%d\n",a)
- #define ptlle(a) printf("%lld\n",a)
- #define debug(...) fprintf(stderr, __VA_ARGS__)
- std::mt19937_64 gen(std::chrono::system_clock::now().time_since_epoch().count());
- ll get(ll l, ll r) { std::uniform_int_distribution
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;
- }