题目链接
题意:
- 给你 N N N个整数,标号为 1 1 1 ~ N N N
- 要求分成无序非空的 k k k组
- 对 M M M取模相同的数字不能分在同一组
- 对 1 ≤ k ≤ n 1 ≤ k ≤ n 1 ≤ k ≤ n 1 \le k \le n 1≤k≤n1≤k≤n都求一次答案
- 2 ≤ N ≤ 5000 , 2 ≤ M ≤ N 2 \le N \le 5000,2 \le M \le N 2≤N≤5000,2≤M≤N
分析:
我们抛开 对
M
M
M取模相同的数字不能分到同一组这个条件。就将其问题转化成 第二类斯特林数,
也就是用
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示:前i个数,选j组,转移方程为:
d
p
[
i
]
[
j
]
=
d
p
[
i
−
1
]
[
j
−
1
]
+
j
∗
d
p
[
i
−
1
]
[
j
]
dp[i][j]=dp[i-1][j-1]+j*dp[i-1][j]
dp[i][j]=dp[i−1][j−1]+j∗dp[i−1][j]
意义:前i个数构成的,我们让第
i
i
i个数单独一组。那么就是
d
p
[
i
−
1
]
[
j
−
1
]
dp[i-1][j-1]
dp[i−1][j−1].我们还可以将第i个数将其放进原本已经形成的j组种,也就是
j
∗
d
p
[
i
−
1
]
[
j
]
j*dp[i-1][j]
j∗dp[i−1][j]
但是现在加上了这个不能取模相等的条件:
所以我们知道影响的是后面这个式子: j ∗ d p [ i − 1 ] [ j ] j*dp[i-1][j] j∗dp[i−1][j].在准确点就是影响了 j j j,需要将 j j j减去,不能取模相等的地方,这就要看我们已经放多少j%m的数了这个我们就一个统计就好了,然后将 j j j变成 j − n u m [ j % m ] j-num[j\%m] j−num[j%m]这就是转移方程:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int mod = 998244353;
const int maxn = 2e5 + 7;
ll n, m;
ll num[maxn],q[maxn];
ll dp[5010][5010];
ll a[maxn];
int main()
{
cin >> n >> m;
for(int i = 1; i <= n; i++)
{
a[i] = i;
num[a[i] % m]++;
}
dp[0][0] = 1;
for(int i=1;i<=n;i++){
for(int j=0;j<=n;j++){
q[j]=0;
}
for(int j=1;j<=n;j++){
dp[j][i]=(dp[j-1][i-1]+dp[j-1][i]*(i-q[a[j]%m])%mod)%mod;
q[a[j]%m]++;
}
}
for(int i=1;i<=n;i++){
cout<<dp[n][i]%mod<<endl;
}
return 0;
}