Codeforces 868D Huge Strings - 位运算 - 暴力

You are given n strings s1, s2, ..., sn consisting of characters 0 and 1m 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.

Input

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.

Output

Print m lines, each should contain one integer — the answer to the question after the corresponding operation.

Example
input
5
01
10
101
11111
0
3
1 2
6 5
4 4
output
1
2
0
Note

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 }
posted @ 2017-10-06 20:32  阿波罗2003  阅读(423)  评论(0编辑  收藏  举报