完全不需要提前计算贡献啊,为什么题解都是。
原题面中的 在这里用 表示。
将 排序后,显然有 DP 设 为考虑前 个,有 组还没有放 ,当前不和谐度之和为 的方案数。转移是显然的,每次加入一个数考虑它是新一组的唯一元素 / 新一组的 / 之前一组的中间值 / 之前一组的 四种情况:
直接这样转移,第三维中途可能会很小 / 很大,所以时间复杂度为 。
但我们可以剪枝啊!有很多状态最终是无法转移到最终合法状态的。
考虑一个状态 能转移到的最小不和谐度。显然,将 后面的 个作前面 组的 ,剩下的单独成组即可。令 ,即最终不和谐度为 。则 时, 才是有用的。
将不等式变形,得到 ,这是 的一个上界。而 的下界 显然是 (在前 个中选最后 个作为 ,剩下的单独成组),又因为 的单调性,所以 (前面 个加起来肯定小于等于后面 个),则 ,对于一对 ,有用的 只有 个。
每次只转移有用的 ,时间复杂度即可减为 。main code:
for (int i = 1;i <= n;i ++){swap(f0, f1);
for (int j = 0;j <= i && j <= n - i;j ++){
int le = sm[i - j] - sm[i], ri = m - sm[i + j] + sm[i];
for (int k = le;k <= ri;k ++){f1[j][k] = 0;
add(f1[j][k], (j + 1ll) * f0[j][k] % mod);
if (j && k + a[i] <= m) add(f1[j][k], f0[j - 1][k + a[i]]);
if (j < n) add(f1[j][k], (j + 1ll) * f0[j + 1][k - a[i]] % mod);
if (i == n && !j) add(ans, f1[j][k]);
}
}
}