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

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

( ext{len}le 14)


(c=a-b),则退位次数是 (c) 的数位和 (/15)(inom{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(inom{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));
}
原文地址:https://www.cnblogs.com/AThousandMoons/p/14918153.html