CF865E Hex Dyslexia【分析性质,状压 dp】

给定两个数字可重集相同的 \(16\) 进制数 \(a,b\) 之差(长度均相同,可以有前导 \(0\)),求最小的 \(b\),需判断无解。

\(\text{len}\le 14\)


\(c=a-b\),则退位次数是 \(c\) 的数位和 \(/15\)\(\binom{13}6\) 枚举退位,就可以知道 \(a_i-b_i\) 的值。

假设 \(b_i=a_{p_i}\),则已知 \(a_i-a_{p_i}\),其中 \(p\) 是排列。

对于每个环,可以减到 \(\min=0\),然后交换一下合并成一整个大环,对这个大环从 \(0\) 的位置开始 dp,记录下当前用了哪些 \(a_i-a_{p_i}\) 即可,如果得到的数位都 \(\in[0,15]\) 说明合法。

然后还可以发现最高位一定是 \(0\):若 \(c\) 的最高位是 \(15\)\(b\) 的最高位只能是 \(0\),否则合法解 \(c/15\) 的最高位是 \(0\)

时间复杂度 \(O(\binom{13}{6}n2^n)\)

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1<<13;
const LL INF = 0x3f3f3f3f3f3f3f3f;
template<typename T>
bool chmin(T &a, const T &b){if(a > b) return a = b, 1; return 0;}
int num(char c){return isdigit(c) ? c-'0' : c-'a'+10;}
char chr(int c){return c < 10 ? c+'0' : c-10+'a';}
int n, m, lim, a[14];
LL dp[N], sum[N], ans = INF;
char s[15];
void dfs(int d, int c){
	if(d == n-1){
		if(a[n-1] < 0 || a[n-1] > 15) return;
		memset(dp, 0x3f, lim<<3);
		sum[0] = a[n-1]; dp[0] = 0;
		for(int i = 1;i < lim;++ i)
			sum[i] = sum[i&i-1] + a[__builtin_ctz(i)];
		for(int i = 0;i < lim;++ i) if(sum[i] >= 0 && sum[i] < 16)
			for(int j = 0;j < n-1;++ j) if(!(i>>j&1))
				chmin(dp[i|(1<<j)], dp[i] + (sum[i]<<(j<<2)));
		chmin(ans, dp[lim-1]);
		return;
	}
	if(c < n-1-d) dfs(d+1, c);
	if(c > 0){
		a[d] -= 16; ++ a[d+1]; dfs(d+1, c-1);
		a[d] += 16; -- a[d+1];
	}
}
int main(){
	scanf("%s", s); n = strlen(s); lim = 1<<n-1;
	for(int i = 0;i < n;++ i) m += a[i] = num(s[n-1-i]);
	if(m % 15){puts("NO"); return 0;}
	dfs(0, m /= 15);
	if(ans == INF) puts("NO");
	else for(int i = n-1;~i;-- i) putchar(chr(ans>>(i<<2)&15));
}
posted @ 2021-06-22 13:18  mizu164  阅读(137)  评论(0编辑  收藏  举报