Loading

CF1456E XOR-ranges

首先发现这种上下界再结合数据范围,显然是让我们把一个数拆成个数不大于 \(2k\) 的段,其中每个段由一段前缀和一段自由段组成。

考虑从高位到低位确定答案。把每个数拆位列出来,发现如果使用前缀 dp 考虑前一个与后一个的答案没用什么进展。而我们如果把相邻的三个列出来,发现如果中间数这个有限制的段最短的话,新的答案贡献只与外面两个数有关。我们发现这种情况是可以拓展归纳的,对于最小化代价我们可以考虑区间 dp,对于一个区间我们关心它的答案,并且我们需要钦定区间左边的位置和右边的位置都还存在限制,那么对于当前左右两边的状态我们需要知道他是贴着 \(l\) 的还是贴着 \(r\) 的,并且最后一个限制的位置是否产生了变化,具体的,设 \(f(i,l,r,p1,p2,q1,q2)\) 表示区间 \([l,r]\) 中的数在前 \(i\) 位已经解除了限制,而 \(l-1\) 的数和 \(r+1\) 的数的限制保持到了第 \(i\) 位,且这两个数在第 \(i\) 位上的数是否产生了变化。

那么如果 \([l,r]\) 在第 \(i\) 位前就已经都解除了限制,那么该段在第 \(i\) 位产生贡献当且仅当 \(l-1\) 上的数和 \(r+1\) 上的数在第 \(i\) 位不同。然后我们有转移:

\[f(i,l,r,p1,p2,q1,q2)\leftarrow f(i+1,l,r,p1,0,q1,0)+val(l-1,r+1,i) \]

而如果区间 \([l,r]\) 存在第 \(i\) 位才解除的数,我们有转移:

\[f(i,l,r,p1,p2,q1,q2)\leftarrow f(i,l,k-1,p1,p2,o,1)+f(i,k+1,r,o,1,q1,q2) \]

然后有一些细节,比如说需要保证该转移合法,并且有的数到最后都没有解除限制,这些都是要考虑的。

时间复杂度 \(\mathcal{O}(n^3k)\),代码:

#include <bits/stdc++.h>
#define int long long
#define ls (p << 1)
#define rs (ls | 1)
#define rep(i, l, r) for (int i = l; i <= r; ++ i)
#define rrp(i, l, r) for (int i = r; i >= l; -- i)
#define pii pair <int, int>
#define eb emplace_back
#define x first
#define y second
#define inf 1000000000
#define linf 1000000000000000000
using namespace std;
typedef long long ll;
constexpr int N = 50 + 5, P = 998244353;
inline int rd () {
	int x = 0, f = 1;
	char ch = getchar ();
	while (! isdigit (ch)) { if (ch == '-') f = -1; ch = getchar (); }
	while (isdigit (ch)) { x = (x << 1) + (x << 3) + ch - 48; ch = getchar (); }
	return x * f;
}
int n, K;
int L[N], R[N], a[N];
int f[N][N][N][2][2][2][2];
void chk (int &x, int y) {
  x = min (x, y);
}
int dfs (int c, int l, int r, int p1, int p2, int q1, int q2) {
  if (c == K) return l > r ? 0 : 1e18;
  int &ret = f[c][l][r][p1][p2][q1][q2];
  if (~ ret) return ret;
  ret = 1e18;
  int vl = ((p1 ? R[l - 1] : L[l - 1]) >> c) ^ p2;
  int vr = ((q1 ? R[r + 1] : L[r + 1]) >> c) ^ q2;
  chk (ret, dfs (c + 1, l, r, p1, 0, q1, 0) + a[c] * (l != 1 && r != n && ((vl ^ vr) & 1)));
  rep (k, l, r) {
    rep (o, 0, 1) {
      if (! c) chk (ret, dfs (c, l, k - 1, p1, p2, o, 0) + dfs (c, k + 1, r, o, 0, q1, q2));
      int w = (o ? R[k] : L[k]) ^ (1ll << c);
      if (L[k] <= (w & (~ ((1ll << c) - 1))) && (w | ((1ll << c) - 1)) <= R[k])
      chk (ret, dfs (c, l, k - 1, p1, p2, o, 1) + dfs (c, k + 1, r, o, 1, q1, q2));
    }
  }
  return ret;
}
int32_t main () {
  // freopen ("1.in", "r", stdin);
  // freopen ("1.out", "w", stdout);
  memset (f, -1, sizeof f);
  n = rd (), K = rd ();
  rep (i, 1, n) L[i] = rd (), R[i] = rd ();
  rep (i, 0, K - 1) a[i] = rd ();
  cout << dfs (0, 1, n, 0, 0, 0, 0);
}
posted @ 2024-11-24 21:39  lalaouye  阅读(4)  评论(0编辑  收藏  举报