[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();
}

相关文章:

  • 2022-12-23
  • 2021-09-28
  • 2021-04-11
  • 2022-01-18
  • 2021-12-29
  • 2021-08-31
猜你喜欢
  • 2022-12-23
  • 2022-02-06
  • 2022-01-28
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案