link
一個高階 trick。考慮 \(+1\) 操作,他會把最低連續一段 \(1\) 改成 \(0\),把原來第一個 \(0\) 改成 \(1\)。注意到此時最低若干位全被覆蓋為了 \(0\),所以可以考慮從高位到低位劃分子問題。
具體的,對於第 \(k\) 位,\(+1\) 操作對其有影響,當且僅當這一位原來是 \(1\) 且 \(0\sim k - 1\) 位向該位進了 \(1\)。
當進了 \(1\) 後,此時 \(0\sim k - 1\) 位上全部都是 \(0\),劃分為子問題。
設 \(f_{i, p, q, S}\) 表示考慮了 \(0\sim i - 1\) 位,將 \(st\) 變為 \(ed\) 並且使用的 XOR 操作集合為 \(S\) 的答案,其中若 \(p = 0\) 則 \(st\) 為起始數字,否則 \(st = 0\) 且操作中沒有向下一位進 \(1\);若 \(q = 0\) 則 \(ed\) 為目標數字,否則 \(ed = 0\) 且操作中恰好一次向下一位進了 \(1\)。
轉移可以考慮第 \(i - 1\) 位的變化,若 \(q\) 次進位後 \(st\) 和 \(ed\) 在 \(0\sim i - 1\) 位恰好匹配了,那麼 \(f_{i, p, q, S} \gets f_{i - 1, p, q, S}\)。
否則 \(0\sim i - 2\) 位可能經過了多次向第 \(i - 1\) 位進 \(1\) 的操作,每進一次 \(0\sim i - 2\) 位都會清零,所以整個轉移應為 \(f_{i, p, q, S_1 \oplus S_2 \oplus \dots \oplus S_k} \gets f_{i - 1, p, 1, S_1} + f_{i - 1, 1, 1, S_2} + \dots + f_{i - 1, 1, q, S_k}\),可以最短路解決,注意判斷一下轉移路徑的合法性。
時間複雜度 \(\mathcal O(2^{2n} \log V)\)。
點選檢視程式碼
#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define mkp make_pair
#define pir pair <ll, ll>
#define pb emplace_back
#define i128 __int128
using namespace std;
const ll inf = 1e18, M = 40;
template <class T>
void rd(T &x) {
char ch; ll f = 0;
while(!isdigit(ch = getchar()))
if(ch == '-') f = 1;
x = ch - '0';
while(isdigit(ch = getchar()))
x = (x << 1) + (x << 3) + ch - '0';
if(f) x = -x;
}
ll n, st, ed, w, a[15], b[15], f[41][2][2][1 << 8], dis[1 << 8];
ll _xor[1 << 8], sum[1 << 8], vis[1 << 8];
void chkmin(ll &x, const ll y) { x = x < y? x : y; }
int main() {
rd(n), rd(st), rd(ed), rd(w);
for(ll i = 1; i <= n; i++) rd(a[i]), rd(b[i]);
memset(f, 0x3f, sizeof f);
for(ll S = 0; S < (1 << n); S++) {
for(ll i = 1; i <= n; i++)
if(S & (1 << i - 1))
_xor[S] ^= a[i], sum[S] += b[i];
f[0][0][0][S] = f[0][1][0][S] = sum[S];
f[0][0][1][S] = f[0][1][1][S] = sum[S] + w;
}
for(ll i = 1; i <= M; i++) {
for(ll p = 0; p < 2; p++) {
for(ll S = 0; S < (1 << n); S++) {
if((((p? 0 : st) ^ ed ^ _xor[S]) >> i - 1) & 1 ^ 1)
chkmin(f[i][p][0][S], f[i - 1][p][0][S]);
if((((p? 0 : st) ^ _xor[S]) >> i - 1) & 1)
chkmin(f[i][p][1][S], f[i - 1][p][1][S]);
}
memset(vis, 0, sizeof vis);
for(ll S = 0; S < (1 << n); S++)
if((((p? 0 : st) ^ _xor[S]) >> i - 1) & 1 ^ 1)
dis[S] = f[i - 1][p][1][S];
else dis[S] = inf;
for(ll o = 0; o < (1 << n); o++) {
ll S = -1;
for(ll T = 0; T < (1 << n); T++)
if(!vis[T] && (S == -1
|| dis[S] > dis[T])) S = T;
vis[S] = 1;
for(ll T = 0; T < (1 << n); T++)
if((_xor[T] >> i - 1) & 1)
chkmin(dis[S ^ T], dis[S] + f[i - 1][1][1][T]);
}
for(ll S = 0; S < (1 << n); S++)
for(ll T = 0; T < (1 << n); T++) {
if(((_xor[T] ^ ed) >> i - 1) & 1)
chkmin(f[i][p][0][S ^ T], dis[S] + f[i - 1][1][0][T]);
if((_xor[T] >> i - 1) & 1 ^ 1)
chkmin(f[i][p][1][S ^ T], dis[S] + f[i - 1][1][1][T]);
}
}
} ll ans = inf;
for(ll S = 0; S < (1 << n); S++)
ans = min(ans, f[M][0][0][S]);
if(ans >= inf) ans = -1;
printf("%lld", ans);
return 0;
}