Problem - A - Codeforces
题意:
思路:
首先读完题目思路肯定就是状压+背包
但是怎么状压
这个和一般的状态压缩不太一样,每个数位的状态有三种,意味着要用三进制的状态压缩
可以这样考虑:99887766554433221100
一共是20位
对于数位7,第一个7为1表示数位7出现了2次,第2个7为1表示数位7出现了1次,两个都是1说明出现了3次
因此对于每个数位,两个都是1的状态直接是非法的,直接筛去即可
然后在转移的时候构造一个新的状态,按背包转移即可
Code:
#include <bits/stdc++.h>
using i64 = long long;
constexpr int N = 1e2 + 10;
constexpr int M = 1e2 + 10;
constexpr int P = 2e2 + 10;
constexpr i64 Inf = 1e18;
constexpr int mod = 998244353;
constexpr double eps = 1e-6;
std::vector<int> state;
int n;
i64 a[N];
i64 dp[(1 << 20)];
void solve() {
std::cin >> n;
for (int i = 1; i <= n; i ++) {
std::cin >> a[i];
}
for (int s = 0; s < (1 << 20); s ++) {
dp[s] = -Inf;
}
dp[0] = 0;
for (int i = 1; i <= n; i ++) {
std::vector<int> cnt(20);
i64 u = a[i];
while(u) {
int num = u % 10;
cnt[num] ++;
u /= 10;
}
for (auto S : state) {
if (dp[S] < 0) continue;
bool ok = true;
int nS = S;
for (int j = 0; j < 10; j ++) {
int c = S >> (j << 1) & 3;
if (cnt[j] + c > 2) {
ok = false;
break;
}else {
nS = (nS & ~(3 << (j << 1))) | ((c + cnt[j]) << (j << 1));
}
}
if (ok) dp[nS] = std::max(dp[nS], dp[S] + a[i]);
}
}
i64 ans = 0;
for (auto S : state) {
ans = std::max(ans, dp[S]);
}
std::cout << ans << "\n";
}
signed main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int t = 1;
std::cin >> t;
for (int s = 0; s < (1 << 20); s ++) {
bool ok = true;
for (int j = 0; j < 10; j ++) {
if (((s >> (j << 1)) & 3) == 3) {
ok = false;
}
}
if (ok) state.emplace_back(s);
}
std::reverse(state.begin(), state.end());
while (t--) {
solve();
}
return 0;
}