题意:给定一个字符串s(1e6),要求找出一个长为k(1e6)的字典序最小串s1使s1与s的每一个长为k的子串至少有一个位置相同;
枚举s的所有k长子串的反码,这n- k + 1个字符串是不能取的;当2^k大于n-k时,可将前个反码全设为0,枚举后个位置,最后取s子串反码没出现过的字典序最小串
#include<bits/stdc++.h>
using namespace std;
const int N = (int)1e6 + 77;
int n, k;
bool ban[N];
char s[N];
int pref[N];
void solve() {
scanf("%d%d", &n, &k);
scanf("%s", s);
int m = 0;
while (m < k && (1 << m) <= n) m++;
for (int i = 0; i <= n && i < (1 << m); i++)
ban[i] = false;
pref[0] = 0;
for (int i = 0; i < n; i++)
pref[i + 1] = pref[i] + (int)(s[i] == '0');
for (int l = 0; l + k <= n; l++) {
if (pref[l] != pref[l + k - m]) continue;//前k-m个反码为全0
int mask = 0;
for (int i = 0; i < m; i++)
if (s[l + k - 1 - i] == '0')
mask ^= 1 << i;
if (mask <= n) ban[mask] = 1;
}
int ans = 0;
while (ans < (1 << m) && ban[ans]) ans++;
if (ans == (1 << m)) {
printf("NO\n");
return;
}
printf("YES\n");
for (int i = 0; i < k - m; i++)
printf("0");
for (int i = m - 1; i >= 0; i--)
printf("%d", (ans >> i) & 1);
printf("\n");
}
int main()
{
int t;
scanf("%d", &t);
while (t--) solve();
return 0;
}