【Codeforces866E_CF866E】Hex Dyslexia(Structure & DP)

It's my first time to write a blog in EnglishChinglish, so it may be full of mistakes in grammar.

Problem:

Codeforces866E

Analysis:

First, we determine (Sgeq T), then (S-T=A), where (A) is the known number, and (S) is shuffled from (T). Then move (T) to the right so we have (S=T+A).

Think about how to calculate (T+A) in writing. If undo all Jinwei (This is Chinese Pinyin. I don't know how to express it in English. Jinwei means if (T_i+A_i) is not less than (16) in hex, then subtract (16) from it and add (1) to (S_{i+1})), then for every digit, it's (T_i+A_i=S'_i) ((S'_i) can be greater than (15) now). Now, (sum T_i + sum A_i = sum S'_i). But because of (S) is shuffled from (T), (sum T_i) should be equal to (sum S_i). Fortunately, every Jinwei can subtract (15) from (sum S'_i), because Jinwei is subtracting (16) from (S'_i) and add (1) to (S'_{i+1}). Thus, possible (S) and (T) exist only when (A) is divisible by (15).

If (A) is divisible by (15), (frac{sum A_i}{15}) is the times that Jinwei happens. We can determine whether a Jinwei happens on a dight one after another. Jinwei can't happen on the hightest dight, so the total number of ways that exactly (frac{sum A_i}{15}) Jinweis happen is (C_{|T|-1}^{frac{sum A_i}{15}}), where (|T|) is the length of (T). It's not greater than (C_{13}^{lfloor frac{13}{2} floor}=1716).

Now we have determined which digits Jinweis happen on, so we can offset the effect of Jinweis by changing (A). Specifically, if a Jinwei happens on the digit (i), so that (T_i+A_i-16=S_i) and (T_{i+1}+A_{i+1}+1=S_{i+1}), we can subtract (16) from (A_i) and add (1) to (A_{i+1}) ( (A_i) now can be more than (15) or less than (0) ) , then for every (i), there's (T_i+A_i=S_i). In this way, every digit will be independent. (From now on, (A) is the changed one. )

Let's try to structure a possible answer. It should be noticed that now there's no Jinwei happens, or the answer is invalid. An useful fact is, there's at least one (T_i) that is (0), or subtract the minimum in (T) from each (T_i) and (S_i), so that every (T_i+A_i=S_i) is valid as well, but we get a less (T). To minimize (T), let's put (0) on the highest digit directly.

Define (f[S]) is the minimum of (T) when the digits in the set (S) have been decided. Because the number on the highest digit must be (0) and there's no need to consider that digit, (S) is not contain the highest digit. Each time we decide put (a) on a digit (i), we'll get a new number (a+A_i) that waiting to be put. This new number after deciding all digits in the set (S) is exactly (sum_{iin S}A_i+A_{|T|-1}) ( (|T|-1) is the highest digit) , because the first number we put is (0), and then we get (A_{|T|-1}); the second number we put is (A_{|T|-1|}) on digit (i) and we get (A_{|T|-1}+A_i) and so on. In the end, because of our way to change (A_i), (sum A_i) must be (0), and (0) has already been put on the highest digit. How lucky we are!

Now the problem is easy. For every (S), choose a digit (i) and try to put the new number (sum[S]) (in the code it's called like that, but I don't know why, maybe because Tzz is a mouther) on it.

For more details, please read the code.

Code:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <set>
using namespace std;

namespace zyt
{
	template<typename T>
	inline bool read(T &x)
	{
		char c;
		bool f = false;
		x = 0;
		do
			c = getchar();
		while (c != EOF && c != '-' && !isdigit(c));
		if (c == EOF)
			return false;
		if (c == '-')
			f = true, c = getchar();
		do
			x = x * 10 + c - '0', c = getchar();
		while (isdigit(c));
		if (f)
			x = -x;
		return true;
	}
	inline bool read(char &c)
	{
		do
			c = getchar();
		while (c != EOF && !isgraph(c));
		return c != EOF;
	}
	template<typename T>
	inline void write(T x)
	{
		static char buf[20];
		char *pos = buf;
		if (x < 0)
			putchar('-'), x = -x;
		do
			*pos++ = x % 10 + '0';
		while (x /= 10);
		while (pos > buf)
			putchar(*--pos);
	}
	inline void write(const char *const s)
	{
		printf("%s", s);
	}
	typedef long long ll;
	const int N = 15, D = 16, INF = 0x3f3f3f3f;
	const ll LINF = 0x3f3f3f3f3f3f3f3fLL;
	int len, arr[N], sum[1 << N];
	ll ans = LINF, dp[1 << N];
	inline bool check(const int a, const int p)
	{
		return a & (1 << p);
	}
	void solve()
	{
		memset(sum, 0, sizeof(int[1 << len]));
		memset(dp, INF, sizeof(ll[1 << len]));
		for (int i = 0; i < (1 << (len - 1)); i++)
		{
			sum[i] = arr[len - 1];
			for (int j = 0; j < len - 1; j++)
				if (check(i, j))
					sum[i] += arr[j];
		}
		dp[0] = 0;
		for (int i = 0; i < (1 << (len - 1)); i++)
		{
			if (sum[i] < 0 || sum[i] >= D || dp[i] > ans || dp[i] == LINF)
				continue;
			for (int j = 0; j < len - 1; j++)
				if (!check(i, j))
					dp[i | (1 << j)] = min(dp[i | (1 << j)], dp[i] + ((ll)sum[i] << (j << 2)));
		}
		ans = min(ans, dp[(1 << (len - 1)) - 1]);
		;
	}
	void dfs(const int pos, const int rest)
	{
		if (pos < 0)
		{
			if (!rest)
				solve();
			return;
		}
		dfs(pos - 1, rest);
		if (pos && rest)
		{
			++arr[pos], arr[pos - 1] -= D;
			dfs(pos - 1, rest - 1);
			--arr[pos], arr[pos - 1] += D;
		}
	}
	int work()
	{
		char c;
		while (read(c))
		{
			if (isdigit(c))
				arr[len++] = c - '0';
			else
				arr[len++] = c - 'a' + 10;
		}
		reverse(arr, arr + len);
		int sum = 0;
		for (int i = 0; i < len; i++)
			sum += arr[i];
		if (sum % (D - 1))
		{
			write("NO");
			return 0;
		}
		dfs(len - 1, sum / (D - 1));
		if (ans == LINF)
			write("NO");
		else
		{
			static char buf[20];
			char *pos = buf;
			while (len--)
				*pos++ = ((ans % D < 10) ? ans % D + '0' : ans % D - 10 + 'a'), ans /= D;
			while (pos > buf)
				putchar(*--pos);
		}
		return 0;
	}
}
int main()
{
	return zyt::work();
}
原文地址:https://www.cnblogs.com/zyt1253679098/p/10418614.html