1 条题解
-
0
不考虑分数相同的情况,这种特殊处理一下即可。
降分数从小到大排序,每个人可能的分数是一个区间,合法当且仅当每个区间的上界都小于下一个区间的下界。
考虑一个人前一个人和后一个人的真实分数的差 ,如果 ,那么当前这个人的分数必须全部公开,否则这个人的分数一定是长为 的区间,必然与前后至少一个有交。在这个结论的基础上不难发现,这个人最多不公开 个分数。所以所有人可以公开的分数总数是 的而不是 。
然后就可以直接 dp 了,设 表示考虑到第 个人,这个人分数的上界是 ,最少公开多少个分数。转移的时候对当前人求一个背包, 表示当前人有 个不公开,公开的分数总和(下界)是 是否可行。这个背包可以用 bitset 优化。精细实现可以做到 。下面代码是 。
#include <bits/stdc++.h> using namespace std; namespace z { const int N = 2e4 + 5, inf = 1e9; struct o { int a[105]; int sum, id; bool operator < (const o &b) const { if(sum == b.sum) return id > b.id; return sum < b.sum; } int& operator [] (int x) { return a[x]; } } a[N]; int f[2][10005]; bool g[205][10005]; bool h[205][10005]; void main() { ios::sync_with_stdio(false); cin.tie(nullptr);cout.tie(nullptr); int n, m, k; cin >> n >> m >> k; for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) { cin >> a[i][j]; a[i].id = i; a[i].sum += a[i][j]; } sort(a + 1, a + n + 1); memset(f, 0x3f, sizeof(f)); f[0][0] = 0; for(int i = 1; i <= n; i++) { for(int j = 1; j <= m * k; j++) f[i - 1 & 1][j] = min(f[i - 1 & 1][j], f[i - 1 & 1][j - 1]); memset(f[i & 1], 0x3f, sizeof(f[i & 1])); int lim = min(m, (i == 1 || i == n ? m : (a[i + 1].sum - a[i - 1].sum) / k)); if(lim) { memset(g, 0, sizeof(g)); g[0][0] = 1; for(int j = 1; j <= m; j++) { for(int l = 0; l <= lim; l++) memset(h[l], 0, sizeof(h[l])); for(int l = 0; l <= lim; l++) { for(int s = 0; s <= m * k; s++) { if(l) h[l][s] |= g[l - 1][s]; if(s >= a[i][j]) h[l][s] |= g[l][s - a[i][j]]; } } for(int l = 0; l <= lim; l++) memcpy(g[l], h[l], sizeof(h[l])); } for(int l = 0; l <= lim; l++) for(int s = 0; s <= m * k; s++) if(g[l][s] && l * k + s <= m * k) { int t = s - (i == 1 ? 0 : (a[i].id > a[i - 1].id)); if(t >= 0) f[i & 1][l * k + s] = min(f[i & 1][l * k + s], f[i - 1 & 1][t] + m - l); } } else { int s = accumulate(a[i].a + 1, a[i].a + m + 1, 0); f[i & 1][s] = f[i - 1 & 1][s - (i == 1 ? 0 : (a[i].id > a[i - 1].id))] + m; } } int ans = 1e9; for(int i = 0; i <= m * k; i++) ans = min(ans, f[n & 1][i]); cout << ans << '\n'; } #undef int } int main() { z::main(); return 0; }
- 1
信息
- ID
- 10188
- 时间
- 6000ms
- 内存
- 1024MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者