[ABC217]G - Groups
题目

\(n\)个人,编号\(i\sim n\),分成\(k\)组(不一定要连续分组),使任意一组内不存在两个人的编号模\(m\)同余,问方案,取模.

输入\(n,m\),输出\(k\)\(1\sim n\)的所有答案.

[ABC217]G - Groups_i++

思路

这题不比F水?

\(f_{i,j}\)表示前\(j\)个人,分成\(i\)组的合法方案数,目标显然为\(f_{i,n},\quad i\in[1,n]\).

考虑从前\(j-1\)个人转移,对于第\(j\)个人,有两种方案:

  1. 单独开一个组,贡献是\(f_{i-1,j-1}\)
  2. 放到前面的某一个组,注意,前面有\(i\)个组,但是有\(\lfloor \frac{j-1}m\rfloor\)个组中存在和\(j\)\(m\)同余的数,所以贡献是\(f_{i,j-1}\cdot (i-\lfloor \frac{j-1}m\rfloor)\).

转移是\(O(1)\)的,复杂度就是\(O(n^2)\).

代码
#include <iostream>
#include <cstdio>
using namespace std;

typedef long long LL;
const LL mod = 998244353;
const int N = 5010;
int n , m;
LL f[N][N];

int main() {
	cin >> n >> m;
	for(int i = 1 ; i <= m ; i++)
		f[1][i] = 1;
	for(int i = 2 ; i <= n ; i++)//i groups
		for(int j = 1 ; j <= n ; j++) {//first j people
			f[i][j] = f[i - 1][j - 1] + f[i][j - 1] * (i - (j - 1) / m) % mod;
			f[i][j] %= mod;
		}
	
	for(int i = 1 ; i <= n ; i++) {
		printf("%d\n" , f[i][n]);
	}
	return 0;
}