很平凡的一道计数啊。
考虑将所有数都减去 \(x\),那么就要求选的数和为 \(0\)。
正负分开考虑,\(0\) 可以任意选。需要多重背包求 \(f_{i,j}\) 表示选 \(1 \sim i\) 的数和为 \(j\) 的方案数。前缀和优化是平凡的。
code
// Problem: D - Multiset Mean
// Contest: AtCoder - AtCoder Regular Contest 104
// URL: https://atcoder.jp/contests/arc104/tasks/arc104_d
// Memory Limit: 1024 MB
// Time Limit: 4000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;
const int maxn = 110;
const int maxm = 1000100;
ll n, m, mod, f[maxn][maxm], g[maxn];
void solve() {
scanf("%lld%lld%lld", &n, &m, &mod);
f[0][0] = 1;
for (int i = 1; i <= n; ++i) {
mems(g, 0);
for (int j = 0; j <= i * (i + 1) / 2 * m; ++j) {
g[j % i] = (g[j % i] + f[i - 1][j]) % mod;
if (j - i * (m + 1) >= 0) {
g[j % i] = (g[j % i] - f[i - 1][j - i * (m + 1)] + mod) % mod;
}
f[i][j] = g[j % i];
}
}
for (int i = 1; i <= n; ++i) {
ll ans = mod - 1;
for (int j = 0; j <= n * (n + 1) / 2 * m; ++j) {
ans = (ans + f[i - 1][j] * f[n - i][j] % mod * (m + 1) % mod) % mod;
}
printf("%lld\n", ans);
}
}
int main() {
int T = 1;
// scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}
- Multiset AtCoder Regular Contest Meanmultiset atcoder regular contest atcoder regular contest 165 minimization atcoder regular contest atcoder regular contest 166 atcoder regular contest degree atcoder regular contest sliding atcoder regular contest 164 atcoder regular contest 167 atcoder regular contest builder subsegments atcoder regular contest