完全不需要提前计算贡献啊,为什么题解都是。

原题面中的 kk 在这里用 mm 表示。

aa 排序后,显然有 DP 设 fi,j,kf_{i, j, k} 为考虑前 ii 个,有 jj 组还没有放 max\max,当前不和谐度之和为 kk 的方案数。转移是显然的,每次加入一个数考虑它是新一组的唯一元素 / 新一组的 min\min / 之前一组的中间值 / 之前一组的 max\max 四种情况:

fi,j,k=(j+1)(fi1,j,k+fi1,j+1,kai)+fi1,j1,k+aif_{i, j, k} = (j + 1)(f_{i - 1, j, k} + f_{i - 1, j + 1, k - a_i}) + f_{i - 1, j - 1, k + a_i}

直接这样转移,第三维中途可能会很小 / 很大,所以时间复杂度为 O(n2ai)O(n^2\sum a_i)

但我们可以剪枝啊!有很多状态最终是无法转移到最终合法状态的。

考虑一个状态 fi,j,kf_{i, j, k} 能转移到的最小不和谐度。显然,将 aia_i 后面的 jj 个作前面 jj 组的 max\max,剩下的单独成组即可。令 sm=p=i+1i+japsm = \sum_{p = i + 1}^{i + j} a_p,即最终不和谐度为 k+smk + sm。则 k+smmk + sm \le m 时,fi,j,kf_{i, j, k} 才是有用的。

将不等式变形,得到 kmsmk \le m - sm,这是 kk 的一个上界。而 kk 的下界 lklk 显然是 p=ij+1iap-\sum_{p = i - j + 1}^i a_p(在前 ii 个中选最后 jj 个作为 min\min,剩下的单独成组),又因为 aa 的单调性,所以 smlkkmsm-sm \le lk \le k \le m - sm(前面 jj 个加起来肯定小于等于后面 jj 个),则 msmlkmsm+sm=mm - sm - lk \le m - sm + sm = m,对于一对 i,ji, j,有用的 kk 只有 O(m)O(m) 个。

每次只转移有用的 kk,时间复杂度即可减为 O(n2m)O(n^2m)。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]);
		}
	}
}