守列划分问题(圆排列+排列dp+结论)
problem
將正整數 1~n1\sim n1~n 任意劃分成 mmm 個非空集合 A1,...,AmA_1,...,A_mA1?,...,Am?。
一個劃分是守序的,當且僅當存在一個環排列 (p1,...,pm)(p_1,...,p_m)(p1?,...,pm?),使得 max?Api>min?Api?1\max A_{p_i}>\min A_{p_{i-1}}maxApi??>minApi?1??。p0=pmp_0=p_mp0?=pm?。
兩個劃分本質不同,當且僅當存在兩個數在一個劃分中屬于同一個集合,而在另一個劃分成屬于不同集合。
求本質不同的守序劃分方案數,對 998244353 取模。
n,m≤500n,m\le 500n,m≤500。
solution
守序的判定可以轉化為:不存在一個 iii,使得 1~i1\sim i1~i 各自隸屬集合的集合 S?S\bigcapS? i+1~ni+1\sim ni+1~n 各自隸屬集合的集合 T=?T=\emptyT=?。
簡單證明一下:不管圓排列是怎樣的,TTT 里面的集合最小值最大值都是 ≥i+1\ge i+1≥i+1,而 SSS 里面的集合最小值最大值都是 ≤i\le i≤i 的,而圓排列至少會讓一個屬于 SSS 的集合在一個屬于 TTT 的集合后一個位置,那么這個時候一定無法滿足條件。
設 f(i,j,k):f(i,j,k):f(i,j,k): 考慮前 iii 個數,一共劃分成了 jjj 個集合,其中有 kkk 個集合還未封閉。區間封閉代表這已經生成了一個集合,之后不會再加數了。
則除了 i=ni=ni=n 時,其余時候是不能 k=0k=0k=0 的。考慮轉移到 f(i,j,k)f(i,j,k)f(i,j,k) 的幾種情況。
- 新增一個封閉區間。f(i?1,j?1,k)f(i-1,j-1,k)f(i?1,j?1,k)。
 - 新增一個未封閉區間。f(i?1,j?1,k?1)f(i-1,j-1,k-1)f(i?1,j?1,k?1)。
 - 隨便加入一個未封閉區間后仍處于未封閉狀態。f(i?1,j,k)×kf(i-1,j,k)\times kf(i?1,j,k)×k。
 - 隨便加入一個未封閉區間后使之封閉。f(i?1,j,k+1)×(k+1)f(i-1,j,k+1)\times (k+1)f(i?1,j,k+1)×(k+1)。
 
code
#include <bits/stdc++.h> using namespace std; #define mod 998244353 #define maxn 505 int dp[maxn][maxn][maxn]; int n, m;signed main() {scanf( "%d %d", &n, &m );dp[0][0][0] = 1;for( int i = 1;i <= n;i ++ )for( int j = 1;j <= m;j ++ )for( int k = ( i != n );k <= j;k ++ ) //在n之前是不能讓集合出現全都封閉的情況dp[i][j][k] = ( 1ll * dp[i - 1][j - 1][k] + 1ll * dp[i - 1][j - 1][max( 0, k - 1 )] + 1ll * dp[i - 1][j][k + 1] * ( k + 1 ) + 1ll * dp[i - 1][j][k] * k ) % mod;//新開一個封閉集合 / 自己單獨為一個集合//新開一個不封閉的集合等待后續的加入//隨便加入一個不封閉的集合使之封閉//隨便加入一個不封閉的集合等待后續加入printf( "%d\n", dp[n][m][0] );return 0; }總結
以上是生活随笔為你收集整理的守列划分问题(圆排列+排列dp+结论)的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: 还记得年少时的梦吗?(文字版)[强烈推荐
 - 下一篇: 后疫情时代 金融行业数字化转型解题