AGC061E 做題記錄

Lgx_Q發表於2024-11-06

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;
}