被训练系统的标签误导,不能用DP求解,这不是一个最值问题,状态复杂不易记录,采用DFS搜索求解。
简要分析:
阅读题意可以发现,在原串中:
- 连续一长串1,且长度大于2时必然会被加密。(如:111 -> 11、1111 -> 100、11111 ->101 等等)
- 单个1、单个0、连续两个1的情况不会被加密。
因而可以推断出,在解密串中:
- 任何以0开头的子串,都是未被加密过的。
- 以1为开头的子串中,长度小于等于2,且不是10的子串都可能是未被加密过的。(如:1、11)
- 以1为开头的子串中,将串认为是二进制数,大于11(十进制的3)的,都可能是被加密过的。(如:11 -> 111、100 -> 1111、101 -> 11111 等等)
根据以上分析,编写 dfs 函数,当搜索时原串的长度和包含1的数量超出限制,或者搜索到两个结果时,立即停止搜索。
另:题目注明了原串长度不超过16 Kbytes,所以解密串时不可能出现大于 128000 的。限制最长解密的最大值为128000。
ANSI C:
#include <stdio.h>
#include <string.h>
char bin[45];
int L, N, binlen;
int ans, one, lens;
void dfs(int i)
{
int j, spans, spone;
if (lens > L || one > N || ans > 1)
return;
if (i == binlen)
{
if (lens + one == L + N)
++ans;
return;
}
if (bin[i] == '0')
{
++lens;
dfs(i + 1);
--lens;
return;
}
for (j = i, spans = 0, spone = 0; j != binlen; ++j)
{
spans = spans * 2 + (bin[j] - '0');
spone += bin[j] - '0';
if (spans > 128000)
return;
if (j + 1 != binlen && bin[j + 1] - '0')
continue;
if (spans > 2)
{
lens += spans, one += spans;
dfs(j + 1);
lens -= spans, one -= spans;
}
if (j - i <= 1 && spans != 2)
{
lens += spone, one += spone;
dfs(j + 1);
lens -= spone, one -= spone;
}
}
}
int main(void)
{
scanf("%d%d%s", &L, &N, bin);
binlen = strlen(bin);
dfs(0);
if (ans > 1)
puts("NOT UNIQUE");
else if (ans < 1)
puts("NO");
else
puts("YES");
return 0;
}