Educational Codeforces Round 101 (Rated for Div. 2) E - A Bit Similar
阿新 • • 發佈:2020-12-29
題目傳送門
很巧妙的一道題。對於一個 \(n\)位的 \(01\)字串,一共有 \(2^n\)種不同字元排列,對於任意一個固定排列,在 \(2^n\)種排列中只有一種排列與該固定排列處處不等,而題幹中的串長不超過 \(1e6\),小於 \(2^{20}\),也就是說所有長度為 \(20\)的子串不超過 \(1e6\)個,那我們只用讓答案串的後 \(20\)位取一個與所有長度為 \(20\)的子串都“相交”的排列,前面都取 \(0\),這樣字典序最小。
記錄下每個長度為 \(20\)的子串它的排斥串,然後列舉 \([1,1<<20)\)找到最小的非排斥串作為答案串後 \(20\)位。注意只有遇見超過 \(k-20\)
#include<cstdio> #include<vector> #include<algorithm> using namespace std; const int N = 1e6 + 5; int T, n, k; char s[N]; bool vis[N]; void solve(){ scanf("%d%d%s", &n, &k, s + 1); int kk = min(k, 20); vector<bool> rej(1 << kk, 0); for(int i = 1, num = 0; i <= n - kk + 1; ++i){ if(num >= k - kk){ int sta = 0; for(int t = 0; t < kk; ++t){ sta = sta * 2 + (s[i + t] != '1'); } rej[sta] = 1; } num = (s[i] == '1' ? num + 1 : 0); } for(int i = 0; i < (1 << kk); ++i){ if(!rej[i]){ puts("YES"); for(int t = 1; t <= k - kk; ++t) putchar('0'); for(int t = kk - 1; ~t; --t) putchar((i & (1 << t)) ? '1' : '0'); puts(""); return ; } } puts("NO"); } int main(){ scanf("%d", &T); while(T--) solve(); return 0; }