题目链接

https://loj.ac/problem/6502

题解

中间一档部分分提示我们将所有的 \(w_i\) 排序。

考虑如果我们能构造出这样一个 \(w_i\) 的序列,使得该序列满足:对于任意的 \(i(1 \leq i \leq n)\),所有的 \(j(1 \leq j < i)\) 都满足 \(w_i + w_j \geq m\) 或者所有的 \(j(1 \leq j < i)\) 都满足 \(w_i + w_j < m\),那么我们就可以使用动态规划求解。

具体地,设 \(f_{i, j}\) 表示处理到了 \(w_i\),且 \(A\) 队中已有 \(j\) 个元素能得到的最大贡献值。若 \(w_i\) 满足对于任意 \(j(1 \leq j < i)\) 有 \(w_i + w_j \geq m\),那么考虑将 \(w_i\) 放入 \(A\) 队,则 \(w_i\) 与前面所有放入 \(B\) 队的 \(i - j\) 个元素都能配合默契,因此有 \(f_{i, j} = f_{i - 1, j - 1} + i - j\);考虑放入 \(B\) 队,则 \(w_i\) 与前面所有放入 \(A\) 队中的 \(j\) 个元素都能配合默契,因此有 \(f_{i, j} = f_{i - 1, j} + j\),最终答案在两者间取 \(\rm max\)。若 \(w_i\) 满足对于任意 \(j(1 \leq j < i)\) 有 \(w_i + w_j < m\),由于无论放入 \(A\) 队还是 \(B\) 队都不能造成贡献,因此转移为 \(f_{i, j} = {\rm max}\{f_{i - 1, j - 1}, f_{i - 1, j}\}\)。求方案数在转移 \(f\) 时一起统计即可。

现在的问题是如何构造这个序列。

我们先将 \(w\) 从小到大排序,发现若 \(w_1 + w_n \geq m\),那么对于任意的 \(j(1 \leq j < n)\) 均满足 \(w_j + w_n \geq m\);若 \(w_1 + w_n < m\),那么对于任意的 \(j(1 < j \leq n)\) 均满足 \(w_1 + w_j < m\),但依然有可能存在 \(j(1 \leq j < n)\) 满足 \(w_j + w_n \geq m\)。

因此,我们可以思考如下算法:对于按从小到大排序后得到的区间 \([l, r]\),若满足 \(w_l + w_r \geq m\),那么弹出 \(w_r\),处理区间 \([l, r - 1]\),否则弹出 \(w_l\),处理区间 \([l + 1, r]\)。每次我们将弹出的数放到一个新的数组 \(p\) 的最左端,那么可以证明,得到的 \(p\) 数组就能够满足我们所需要的性质。

我们求出数组 \(p\) 后,就能够通过 dp 在 \(O(n^2)\) 的时间内解决此题了。

代码

#include<bits/stdc++.h>

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define debug(...) fprintf(stderr, __VA_ARGS__) typedef long long ll;
typedef long double ld;
typedef unsigned int uint;
typedef pair<int, int> pii;
typedef unsigned long long ull; template<typename T> inline void read(T& x) {
char c = getchar();
bool f = false;
for (x = 0; !isdigit(c); c = getchar()) {
if (c == '-') {
f = true;
}
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - '0';
}
if (f) {
x = -x;
}
} template<typename T> inline bool checkMax(T& a, const T& b) {
return a < b ? a = b, true : false;
} template<typename T> inline bool checkMin(T& a, const T& b) {
return a > b ? a = b, true : false;
} const int N = 2e3 + 10, mod = 1e9 + 7; inline void add(int& x, int y) {
x = (x + y) % mod;
} int n, m, a[N], all[N], f[N][N], g[N][N]; int main() {
read(n), read(m);
for (register int i = 1; i <= n; ++i) {
read(a[i]);
}
sort(a + 1, a + 1 + n);
int l = 1, r = n;
for (register int i = n; i; --i) {
if (a[l] + a[r] >= m) {
all[i] = 1, --r;
} else {
all[i] = 0, ++l;
}
}
int ans = 0;
g[0][0] = 1;
for (register int i = 1; i <= n; ++i) {
for (register int j = 0; j <= i; ++j) {
if (j ^ i) {
int v = f[i - 1][j] + (all[i] ? j : 0);
if (v > f[i][j]) {
f[i][j] = v, g[i][j] = g[i - 1][j];
} else if (v == f[i][j]) {
add(g[i][j], g[i - 1][j]);
}
} if (j) {
int v = f[i - 1][j - 1] + (all[i] ? i - j : 0);
if (v > f[i][j]) {
f[i][j] = v, g[i][j] = g[i - 1][j - 1];
} else if (v == f[i][j]) {
add(g[i][j], g[i - 1][j - 1]);
}
}
checkMax(ans, f[i][j]);
}
}
int res = 0;
for (register int i = 0; i <= n; ++i) {
if (f[n][i] == ans) {
add(res, g[n][i]);
}
}
printf("%d %d\n", ans, res);
return 0;
}

最新文章

  1. 【iCore3 双核心板_FPGA】实验二十八:基于SDRAM 的VGA 驱动器的设计
  2. jQuery管理包装集笔记
  3. 【zTree】 zTree使用的 小例子
  4. POJ 1625 Censored!(大数+DP)
  5. python学习进阶一
  6. ABAP OO与ALV结合方式探索(1)
  7. 为什么多数游戏服务端是用 C++ 来写
  8. T-SQL实例 函数结果设置为列别名
  9. leetcode面试准备:Lowest Common Ancestor of a Binary Search Tree &amp; Binary Tree
  10. (简单) POJ 2253 Frogger,Dijkstra。
  11. K:平衡二叉树(AVL)
  12. 部署Openfire3.9.3源码部署
  13. celery异步消息处理框架
  14. C# HTTP上传多个文件及传递参数
  15. 针对SSL/TLS的拒绝服务攻击以及使用ettercap进行DNS欺骗
  16. 12、JAVA内存模型与线程
  17. 如何在Windows中使用netsh命令进行端口转发
  18. Numpy学习50例
  19. C++ Primer Plus学习:第一章
  20. [实践]使用JarJar优雅的发布依赖包

热门文章

  1. mysql 索引 笔记1
  2. 图解KMP算法
  3. c语言实践 打印字母三角形
  4. Luogu 4091 [HEOI2016/TJOI2016]求和
  5. JavaScript 的 export default 命令
  6. redis内存优化方法
  7. initWithFrame 和 initWithCoder 区别?
  8. jquery表单数据验证扩展方法
  9. QT背景
  10. python -Tkinter 实现一个小计算器功能