[CF1439D] INOI Final Contests

[题目链接]

https://codeforces.com/contest/1439/problem/D

[题解]

首先解决 (N = M) 的情况。

不妨设 (dp1_{i}) 表示 (i) 个人 (i) 个座位的合法方案数 , 枚举最后一个人坐的位置。 由于左右两侧独立 , 得到

(dp1_{i}=sumlimits_{j=1}^i [j+(i-j+1)]{i-1choose j-1}dp1_{j-1}dp1_{i-j})

(dp2_{i}) 表示 (i) 个人 (i) 个座位 , 所有情况的移动距离之和。 枚举最后一人的座位 , 单独考虑其贡献 , 得到

(dp2_{i}=sumlimits_{j=1}^i ({jchoose 2}+{i-jchoose 2}){i-1choose j-1}dp1_{j-1}dp1_{i-j}+[j+(i-j+1)]{i-1choose j-1}(dp2_{j-1}dp1_{i-j}+dp2_{i-j}dp1_{j-1}))

接着 , 考虑 (N > M) 的情况。

(dp3_{i , j}) 表示前 (i) 个人 , (j) 个座位被占用的方案数 , 枚举末尾极长一段被连续占用的座位 , 得到

(dp3_{i,j}=dp3_{i-1,j}+sumlimits_{l=1}^j {jchoose l}dp3_{i-l-1,j-l}cdot dp1_{l})

类似地 , 令 (dp_{i , j}) 表示前 (i) 个人 , (j) 个座位被占用的移动距离和 , 易知

(dp4_{i,j}=dp4_{i-1,j}+sumlimits_{l=1}^j {jchoose l}(dp4_{i-1-l,j-l}cdot dp1_{l}+dp3_{i-1-l,j-l}dp2_l))

这个做法的时间复杂度 (O(NM))。 事实上可以通过多项式做法优化至 (O(NlogN))

[代码]

#include<bits/stdc++.h>
 
using namespace std;
 
typedef long long LL;
 
#define rep(i , l , r) for (int i = (l); i < (r); ++i)
 
const int MN = 505;
 
int N , M , mod , dp1[MN] , dp2[MN] , dp3[MN][MN] , dp4[MN][MN] , C[MN][MN];
 
inline void inc(int &x , int y) {
	x = x + y < mod ? x + y : x + y - mod; 
}
 
int main() {
	 
	 scanf("%d%d%d" , &N , &M , &mod);
	 for (int i = 0; i <= 500; ++i) {
	 	 C[i][0] = C[i][i] = 1;
	 	 for (int j = 1; j < i; ++j) C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
	 }
	 dp1[0] = 1;
	 for (int i = 1; i <= 500; ++i) {
	 	for (int j = 1; j <= i; ++j)
	 	    inc(dp1[i] , 1ll * dp1[j - 1] * dp1[i - j] % mod * C[i - 1][j - 1] % mod);
	 	dp1[i] = 1ll * dp1[i] * (i + 1) % mod;
	 	for (int j = 1; j <= i; ++j) {
	 		inc(dp2[i] , 1ll * (i + 1) * C[i - 1][j - 1] % mod * (1LL * dp1[j - 1] * dp2[i - j] % mod + 1LL * dp2[j - 1] * dp1[i - j] % mod) % mod);
			inc(dp2[i] , 1ll * C[i - 1][j - 1] * dp1[j - 1] % mod * dp1[i - j] % mod * (j * (j - 1) / 2 + (i - j) * (i - j + 1) / 2) % mod); 	
		}
	 }
	 dp3[0][0] = 1;
	 for (int n = 1; n <= 500; ++n) {
	 	 for (int m = 0; m < n; ++m) {
	 	 	dp3[n][m] = dp3[n - 1][m];
			dp4[n][m] = dp4[n - 1][m];
			for (int i = 1; i <= m; ++i) {
				inc(dp3[n][m] , 1ll * dp3[n - i - 1][m - i] * dp1[i] % mod * C[m][i] % mod);
				inc(dp4[n][m] , 1ll * dp3[n - i - 1][m - i] * dp2[i] % mod * C[m][i] % mod);
				inc(dp4[n][m] , 1ll * dp4[n - i - 1][m - i] * dp1[i] % mod * C[m][i] % mod);
			}	 
		 }
		 dp3[n][n] = dp1[n] , dp4[n][n] = dp2[n];
	 }
	 printf("%d
" , dp4[N][M]);
     return 0;
}
原文地址:https://www.cnblogs.com/evenbao/p/14438718.html