[CF1469E] A Bit Similar - hash
Description
给定长度为 n 的二进制串 a,求字典序最小的长度为 k 的串 b 使得 a 的任意一个长度为 k 的子串与 b 至少有一个字符相同。
Solution
a 的长度为 k 的本质不同子串数量是 O(n) 的
也就是说,O(n) 个长度为 k 的不同的串中,一定能找到一个与 inv(a) 的所有 k 子串不完全相同,也就是与 a 的所有 k 子串至少有一个公共字母
只需要升序枚举二进制串 b 的最后几位,判断是否有过即可
具体地,设我们要枚举的二进制串长度为 m=min(k,20),如果某个位置之前连续已经有了 k-m 个 1,才需要考虑他,否则前面已经有一个 0,和 b 的前面的大段的 0 必有交
对于需要考虑的,我们算出它的十进制表示,取反,得到的是一个禁止点,也就是我们最后不能使用这个串
因为只要和反有一个字符不同,就和原有至少一个字符相同,这样就符合题意了
最后我们升序枚举所有的串,找到第一个没有被禁止的,就是答案
#include <bits/stdc++.h>
using namespace std;
void solve()
{
int n, k;
cin >> n >> k;
int m = min(k, 20); // 要枚举的串的长度
string str;
cin >> str;
int cont_1 = 0;
vector<bool> f(1 << m);
for (int i = 0; i + m - 1 < str.length(); i++)
{
if (cont_1 >= k - m)
{
// 前面 k-m 个位置全是 1,会贡献
int hash = 0;
for (int j = 0; j < m; j++)
{
hash = hash * 2 + '1' - str[i + j];
}
f[hash] = 1;
}
if (str[i] == '1')
cont_1++;
else
cont_1 = 0;
}
for (int i = 0; i < 1 << m; i++)
{
if (f[i] == 0)
{
cout << "YES" << endl;
for (int i = 0; i < k - m; i++)
cout << 0;
for (int j = m - 1; j >= 0; j--)
cout << ((i >> j) & 1);
cout << endl;
return;
}
}
cout << "NO" << endl;
}
signed main()
{
ios::sync_with_stdio(false);
int t;
cin >> t;
while (t--)
solve();
}