题意
题目大意已经说得很清楚了
题解
神仙套路 DP?????
首先不考虑顺序的话就是直接把原数组从小到大排个序
然后考虑DP就相当于是括号匹配
好像有点抽
左括号的代价就是负的,然后右括号的代价就是正的
转移十分简单
答案就是
然后可以发现这个转移是
的,但是状态数是
发现直接GG了
通过题目可以发现 也就是说最后状态代价最多只有 是有用的,但是上面转移 的范围是 会逝世
正解
考虑差分,那原来最大值减最小值就可以转换为差分数组的一段的和
那样就只有加没有减了
考虑转移
和上面的差不多,比较麻烦的就是代价的计算
就是当前差分乘上还没有被匹配的集合的个数
即
然后转移就和账面一毛一个样了
code:
#include<bits/stdc++.h>
#define ll long long
#define N 505
#define mod 1000000007
using namespace std;
void Add(int &x, int y) {
x += y;
if(x >= mod) x-= mod;
}
int n, m, dp[2][N][N << 1], a[N];
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
sort(a + 1, a + 1 + n);
dp[0][0][0] = 1;
for(int i = 0; i < n; i ++) {
int fr = i & 1, to = fr ^ 1;
memset(dp[to], 0, sizeof dp[to]);
for(int j = 0; j <= n; j ++) {
for(int k = 0; k <= m; k ++) {
int nxt = k; Add(nxt, (ll)(a[i + 1] - a[i]) * j);
if(nxt > m || !dp[fr][j][k]) continue;//printf("%d %d %d %d %d %d\n", fr, to, j, k, nxt, i);
Add(dp[to][j + 1][nxt], dp[fr][j][k]); // zi li yi zu
if(j) Add(dp[to][j - 1][nxt], (ll)dp[fr][j][k] * j % mod);// xiao yi zu
Add(dp[to][j][nxt], (ll)dp[fr][j][k] * (j + 1) % mod); // bu xuan huo zuo wei zhong jian zhi
}
}
}
int ans = 0;
for(int i = 0; i <= m; i ++) Add(ans, dp[n & 1][0][i]);
printf("%d", ans);
return 0;
}
总结
我写DP像***
对于这种DP要把状态巧妙转化一下
转化的方法一般有
- 把贡献拆开
- 差分
- 看题解(呸