考虑到合法最大状态一定是某个禁用状态 {a} 的某个元素减一,即把某个 ai 变成 ai−1。
因此选择遍历每个禁用状态和状态的每个元素来求解。
由于用了 map,复杂度 O(nmlogn)(其实原本用的是hash,但是被毒瘤 CF 卡了)
然而不知道为什么 WA 了 #44, 求各路巨神帮忙看看
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <map>
using namespace std;
using LL = long long;
using PII = pair<int, int>;
using PLL = pair<LL, LL>;
int read() {
int s = 0, f = 1;
char ch = getchar();
for (; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') f = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar()) s = (s << 1) + (s << 3) + (ch ^ 48);
return s * f;
}
int n, m;
vector<int> p[20]; // 记录每个槽可以放的物品
int c[100010][20]; // 禁用状态
int path[20]; // 记录答案
map<vector<int>, bool> Map; // 记录禁用状态
LL get_ans(int *c) {
LL res = 0;
for (int i = 1; i <= n; i ++ )
res = res + p[i][c[i] - 1];
return res;
}
void copy(int *path, int *c) {
for (int i = 1; i <= n; i ++ )
path[i] = c[i];
}
void insert(int *a) { // 插入某个禁用状态
vector<int> k;
for (int i = 1; i <= n; i ++ ) k.push_back(a[i]);
Map[k] = true;
}
bool check(int *a) { // 检查某个状态是否是禁用状态
vector<int> k;
for (int i = 1; i <= n; i ++ ) k.push_back(a[i]);
return Map[k];
}
int main() {
n = read();
for (int i = 1; i <= n; i ++ ) {
int len = read();
while (len -- ) p[i].push_back(read());
}
m = read();
for (int i = 1; i <= m; i ++ ) {
for (int j = 1; j <= n; j ++ ) c[i][j] = read();
insert(c[i]);
}
for (int i = 1; i <= n; i ++ ) path[i] = p[i].size();
if (!check(path)) {
for (int i = 1; i <= n; i ++ ) printf("%d ", path[i]);
return 0;
}
LL ans = -100;
for (int i = 1; i <= m; i ++ ) { // 遍历每个禁用状态
for (int j = 1; j <= n; j ++ ) { // 遍历禁用状态的每个元素
if (c[i][j] == 1) continue;
c[i][j] -- ;
if (check(c[i])) continue;
if (get_ans(c[i]) > ans) {
ans = get_ans(c[i]);
copy(path, c[i]);
}
c[i][j] ++ ;
}
}
for (int i = 1; i <= n; i ++ ) printf("%d ", path[i]);
return 0;
}