【思路要点】
- 首先差分序列,此时序列中至多存在 2 K 2K 2K 个 1 1 1 。
- 剩余的过程可以看做选定一个 1 1 1 ,并将其移动在集合 { a i } \{a_i\} {ai} 中的距离。
- 预处理每两个 1 1 1 之间的操作距离,然后状压 d p dp dp 即可。
- 时间复杂度 O ( N × L × K + K × 4 K ) O(N\times L\times K+K\times 4^{K}) O(N×L×K+K×4K) 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 1e4 + 5; const int MAXS = 1 << 20; const int MAXM = 25; const int INF = 1e8; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } int n, m, k, l, a[MAXN], b[MAXN], dp[MAXS]; int dist[MAXN], mp[MAXM][MAXM], bit[MAXM]; bool vis[MAXN]; int getans(int s) { if (s == 0) return 0; if (dp[s] != -1) return dp[s]; int ans = INF; for (int i = 1; i <= m; i++) if (bit[i] & s) { for (int j = i + 1; j <= m; j++) if (bit[j] & s) chkmin(ans, mp[i][j] + getans(s ^ bit[i] ^ bit[j])); break; } return dp[s] = ans; } int main() { freopen("z.in", "r", stdin); freopen("z.out", "w", stdout); read(n), read(k), read(l); for (int i = 1; i <= k; i++) { int x; read(x); vis[x] = true; } for (int i = n + 1; i >= 1; i--) { vis[i] ^= vis[i - 1]; if (vis[i]) a[++m] = i; } for (int i = 1; i <= l; i++) read(b[i]); for (int i = 1; i <= m; i++) { memset(dist, -1, sizeof(dist)); deque <int> q; q.push_back(a[i]); dist[a[i]] = 0; while (!q.empty()) { int pos = q.front(); q.pop_front(); for (int i = 1; i <= l; i++) { if (pos - b[i] >= 1 && dist[pos - b[i]] == -1) { dist[pos - b[i]] = dist[pos] + 1; q.push_back(pos - b[i]); } if (pos + b[i] <= n + 1 && dist[pos + b[i]] == -1) { dist[pos + b[i]] = dist[pos] + 1; q.push_back(pos + b[i]); } } } for (int j = 1; j <= m; j++) if (j != i && dist[a[j]] != -1) mp[i][j] = dist[a[j]]; else mp[i][j] = INF; } memset(dp, -1, sizeof(dp)); for (int i = 1; i <= m; i++) bit[i] = 1 << (i - 1); int ans = getans((1 << m) - 1); if (ans >= INF) writeln(-1); else writeln(ans); return 0; }