Codeforces 868D Huge Strings - 位运算 - 暴力
You are given n strings s1, s2, ..., sn consisting of characters 0 and 1. m operations are performed, on each of them you concatenate two existing strings into a new one. On the i-th operation the concatenation saisbi is saved into a new string sn + i (the operations are numbered starting from 1). After each operation you need to find the maximum positive integer k such that all possible strings consisting of 0 and 1 of length k (there are 2k such strings) are substrings of the new string. If there is no such k, print 0.
The first line contains single integer n (1 ≤ n ≤ 100) — the number of strings. The next n lines contain strings s1, s2, ..., sn (1 ≤ |si| ≤ 100), one per line. The total length of strings is not greater than 100.
The next line contains single integer m (1 ≤ m ≤ 100) — the number of operations. m lines follow, each of them contains two integers aiabd bi (1 ≤ ai, bi ≤ n + i - 1) — the number of strings that are concatenated to form sn + i.
Print m lines, each should contain one integer — the answer to the question after the corresponding operation.
5
01
10
101
11111
0
3
1 2
6 5
4 4
1
2
0
On the first operation, a new string "0110" is created. For k = 1 the two possible binary strings of length k are "0" and "1", they are substrings of the new string. For k = 2 and greater there exist strings of length k that do not appear in this string (for k = 2 such string is "00"). So the answer is 1.
On the second operation the string "01100" is created. Now all strings of length k = 2 are present.
On the third operation the string "1111111111" is created. There is no zero, so the answer is 0.
题目大意 有n个01字符串,第i个操作是生成第n + i个字符串,方式是将两个已经存在的字符串拼接到一起,然后询问最大的k使得所有长度为k的01串都在这个串中出现过。
范围很吓人,意味着最大可能你需要判断2100个串是否存在(和同学组队开黑的时候被吓坏了。。懵逼了好久。),然而事实上。。答案都非常小。至少我没有找到一个超过10的。
另外注意到是拼接,所以串内部的情况不变,唯一增加新出现的子串的地方是拼接处,因为已经知道答案很小,就直接暴力就好了。
另外注意一个细节,就是用位运算弄得时候记得在开头加一个1,不然它会认为01和001是同一个串,但是101中并不存在串001。
(个人认为这道题的难点就在于估计答案范围,猜到很小就乱搞就好了,方法很多,什么记忆化搜索+二分也可以)
下面是答案会比较小的证明:(感谢我的学长idy002)
考虑长度为k的01串,在两个串进行合并的时候,两个串内部包含的本质不同的串是不变的,所以不会增加。因此新增加的子串一定是跨过交界处。
所以最多有(k - 1)个新增的本质不同的01串。再加上原本的包含为k的本质不同的01串的个数,可以列得不等式:
解不等式得到k不会超过11。
Code
1 /** 2 * Codeforces 3 * Problem#868D 4 * Accepted 5 * Time: 30ms 6 * Memory: 1700k 7 */ 8 #include <bits/stdc++.h> 9 using namespace std; 10 typedef bool boolean; 11 12 #define limlen 15 13 14 typedef class String { 15 public: 16 string pre, suf; 17 boolean overflow; 18 int rt; 19 bitset<65536> mark; 20 21 String():overflow(false) { } 22 }String; 23 24 String operator + (String& a, String& b) { 25 String rt; 26 rt.overflow = a.overflow || b.overflow; 27 rt.mark = a.mark | b.mark; 28 if(!a.overflow) { 29 rt.pre = a.pre + b.pre; 30 if(rt.pre.length() > limlen) 31 rt.overflow = true, rt.pre.resize(limlen); 32 } else rt.pre = a.pre; 33 if(!b.overflow) { 34 rt.suf = a.suf + b.suf; 35 if(rt.suf.length() > limlen) 36 rt.overflow = true, rt.suf = rt.suf.substr(rt.suf.size() - limlen, rt.suf.size()); 37 } else rt.suf = b.suf; 38 39 string s = a.suf + b.pre; 40 for(int i = 0; i < s.length(); i++) 41 for(int j = 0, t = 0; j < limlen && i + j < s.length(); j++) { 42 t = (t << 1) | (s[i + j] & 1); 43 rt.mark[t | (1 << (j + 1))] = 1; 44 } 45 46 int i; 47 for(rt.rt = 0; ; rt.rt++) { 48 for(i = 0; i < (1 << rt.rt + 1) && rt.mark[i | (1 << rt.rt + 1)]; i++); 49 if(!rt.mark[i | (1 << rt.rt + 1)]) 50 break; 51 } 52 return rt; 53 } 54 55 int n, m; 56 String strs[205]; 57 58 inline void init() { 59 cin >> n; 60 for(int i = 1; i <= n; i++) { 61 cin >> strs[i].pre; 62 strs[i].suf = strs[i].pre; 63 strs[i].mark[1] = 1; 64 for(int j = 0; j < strs[i].pre.length(); j++) 65 for(int k = 0, t = 0; k < limlen && j + k < strs[i].pre.length(); k++) { 66 t = (t << 1) | (strs[i].pre[j + k] & 1); 67 strs[i].mark[t | (1 << (k + 1))] = 1; 68 } 69 } 70 } 71 72 inline void solve() { 73 cin >> m; 74 for(int i = 1, a, b; i <= m; i++) { 75 cin >> a >> b; 76 strs[n + i] = strs[a] + strs[b]; 77 cout << strs[n + i].rt << endl; 78 } 79 } 80 81 int main() { 82 ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); 83 init(); 84 solve(); 85 return 0; 86 }