AT3962 [AGC024E] Sequence Growing Hard 題解
阿新 • • 發佈:2021-10-14
Link.
Description.
給定 \(n,k,m\),統計序列序列數 \(\{A_i(i\in[0,n])\}\),使得
- \(\text{size}(A_i)=i\)
- \(\forall i\in[1,n],j\in[1,i],A_i(j)\in[1,k]\)
- \(\forall i\in[1,n]\),\(A_{i-1}\) 是 \(A_i\) 的子序列且字典序小於 \(A_i\)
Solution.
自己的想法:
題意轉化成了求不同操作序列數
- 每次末尾插入一個任意元素
- 每次在第 \(k\) 個位置插入一個權值 \(>a_k\) 的元素
題解:
發現在開頭插個 \(0\)
然後考慮建樹,一個點向它插入位置連邊,還要記錄一個當前是第幾次操作。
本質上來說,一個點當前第幾次操作其實在樹的形態確定時是基本確定的。
只能在所有兒子改變順序時才能變。
那我們考慮記錄 \(dp_{x,y}\) 表示大小為 \(x\) 根權為 \(y\) 的子樹的方案數。
我們列舉第一個子樹是什麼,然後刪掉後 \(dp\) 狀態是已知的。
列舉第一個子樹的大小和根權,則有
Coding.
點選檢視程式碼
//是啊,你就是那隻鬼了,所以被你碰到以後,就輪到我變成鬼了{{{ #include<bits/stdc++.h> using namespace std;typedef long long ll; template<typename T>inline void read(T &x) { x=0;char c=getchar(),f=0; for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1; for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48); f?x=-x:x; } template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}} int n,K,P,dp[305][305],sm[305][305],C[305][305]; inline void upd(int &a,int b) {(a+=b)>=P?a-=P:a;} int main() { read(n,K,P);for(int i=K;i>=0;i--) sm[1][i]=sm[1][i+1]+(dp[1][i]=1); for(int i=0;i<=n;i++) {C[i][0]=1;for(int j=1;j<=i;j++) upd(C[i][j]=C[i-1][j-1],C[i-1][j]);} for(int i=2;i<=n+1;i++) for(int j=K;j>=0;upd(sm[i][j]=sm[i][j+1],dp[i][j]),j--) for(int l=1;l<i;l++) upd(dp[i][j],1ll*C[i-2][l-1]*dp[i-l][j]%P*sm[l][j+1]%P); return printf("%d\n",dp[n+1][0]),0; }