【校内训练2019-06-26】Z

【思路要点】

  • 首先差分序列,此时序列中至多存在 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值