问题描述
数据压缩的目的是为了减少存储和交换数据时出现的冗余。这增加了有效数据的比重并提高了传输速率。有一种压缩二进制串的方法是这样的:
将连续的n个1替换为n的二进制表示(注:替换发生当且仅当这种替换减少了二进制串的总长度)
(译者注:连续的n个1的左右必须是0或者是串的开头、结尾)
比如:11111111001001111111111111110011会被压缩成10000010011110011。原串长为32,被压缩后串长为17.
这种方法的弊端在于,有时候解压缩算法会得到不止一个可能的原串,使得我们无法确定原串究竟是什么。请你写一个程序来判定我们能否利用压缩后的信息来确定原串。给出原串长L,原串中1的个数N,以及压缩后的串。
L<=16 Kbytes,压缩后的串长度<=40 bits。
输入格式
第一行两个整数L,N,含义同问题描述
第二行一个二进制串,表示压缩后的串
输出格式
输出 "YES" 或 "NO" 或 "NOT UNIQUE"(不包含引号)
分别表示:
YES:原串唯一
NO:原串不存在
NOT UNIQUE:原串存在但不唯一
样例输入
样例1:
32 26
10000010011110011
样例2:
9 7
1010101
样例3:
14 14
111111
样例输出
样例1:YES
样例2:NOT UNIQUE
样例3:NO
—————————————————————————————————
思路
数据范围较小,可以直接 BFS 暴力构造答案
node 结构体里的 p、l、n 分别表示当前压缩串处理了 p 位,原串构造了前 l 位,其中有 n 个 1
如果当前节点状态超过越界,则舍弃,若还能切分构造则继续加入队列,正好符合答案则 ans++
注意原串中连续的 1 必须被 0 分隔,所以 node 中的 v 标识已还原的最末字符串是否是 1
接下来遇到 0 时就把 v 清零。最后根据 ans 的值输出相应的结果
代码如下
#include <bits/stdc++.h>
#define MAXN 233
using namespace std;
struct node { int p,l,n,v; };
queue<node> Q;
int l,n,len,ans; char v[MAXN];
inline int fun(int s,int t) { // 二进制转换成十进制
int ret=1;
for (int i=s+1;i<=t;i++) {
if (v[i]=='1') ret=(ret<<1)+1;
else ret<<=1;
}
return ret;
}
int main() {
scanf("%d%d%s",&l,&n,v+1),len=(int)strlen(v+1);
Q.push((node){0,0,0,0});
while (!Q.empty()) {
node now=Q.front(); Q.pop();
while (v[now.p+1]=='0' && now.p<len) now.p++,now.l++,now.v=0; // 把接下来的 0 都略过,累计未压缩 0 的长度
if (now.p==len && now.l==l && now.n==n) { ans++; continue; } // 正好符合题意
//此时 v[now.p+1] = '1'
for (int i=now.p+1;!now.v && i<=len;i++) {
int t=fun(now.p+1,i); // 视为压缩后的 1 的长度 -> [now.p+1,i]
//此时 t 为要加入原串中的 1 的长度
if (now.l+t<=l && now.n+t<=n) Q.push((node){i,now.l+t,now.n+t,1});
}
}
if (ans==1) puts("YES");
else puts(ans?"NOT UNIQUE":"NO");
return 0;
}