Codeforces 868D (Codeforces Round #438 D) Huge Strings 分治+哈希

来源:互联网 发布:农村淘宝服务站申请表 编辑:程序博客网 时间:2024/05/20 22:04

D. Huge Strings
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

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 ai abd 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
5011010111111031 26 54 4
output
120
Note

On the first operation, a new string "0110" is created. For k = 1 the two possible binary strings of length kare "0" and "1", they are substrings of the new string. For k = 2 and greater there exist strings of length kthat 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串,有m次合并操作,第 i 次合并选择n个串和之前合并i-1个串当中的两个,问每次合并后的新串是否含有所有长度为k的01串,如果是,输出最大的k,否则输出0.


这道题和之前的一道树分治题目挺像。    戳这里

首先二分答案k,验证所有长度为k的不同子串是否有2^k个。对当前串进行dfs,不断将当前串分成之前的串。对于当前串,假设两个原串的所有长度为k的串都已经考虑过,那么只需要考虑新合成的那部分对于答案的影响。如果我们将长度为100的串反复翻折100次,那么它最多有100*(2^100)个字符,所以k最大为100.那么,新合成的长度为k的串,只要考虑左边原串的后k-1个字符和右边原串的前k-1个字符合并产生的结果,所以我们只要不停的dfs,每次把新合成的串加入哈希表计数,直到串不能再分,再把不能再分的串加入哈希表。这样,就验证了所有长度为k的不同子串。

对于编号固定的串,搜过一次就不需要再搜。这样,每次最多搜200个串,每个串最多哈希表计数100次,100个询问,复杂度是200*100*100=2000000. 实际上,由于哈希表的实现需要时间,最后跑了1s左右.

比赛的时候偷了个懒,哈希表用unordered_map替代了。


#include <cstdio>#include <iostream>#include <string.h>#include <string> #include <map>#include <queue>#include <deque>#include <vector>#include <set>#include <algorithm>#include <math.h>#include <cmath>#include <stack>#include <iomanip>#include <unordered_map>#define mem0(a) memset(a,0,sizeof(a))#define meminf(a) memset(a,0x3f,sizeof(a))using namespace std;typedef long long ll;typedef long double ld;typedef double db;const int maxn=105,inf=0x3f3f3f3f;  const ll llinf=0x3f3f3f3f3f3f3f3f;   const ld pi=acos(-1.0L);string a[maxn*2][2];int lc[maxn*2],rc[maxn*2],len[maxn*2];bool visit[maxn * 2];unordered_map<string,int> mp;ll cnt;void dfs(int now,int k) {if (visit[now]) return;visit[now] = 1;if (lc[now]==0) {for (int i=0;i+k<=len[now];i++) {string s=a[now][0].substr(i,k);//cout << s << endl;    if (mp[s]==0) {    mp[s]++;cnt++;    }    }} else {string s=a[lc[now]][1]+a[rc[now]][0];int le=s.length();for (int i=0;i+k<=le;i++) {string t=s.substr(i,k);//cout << t << endl;    if (mp[t]==0) {    mp[t]++;cnt++;    }    }dfs(lc[now], k); dfs(rc[now], k);}}bool check(int k,int n) {mp.clear();mem0(visit);cnt=0;dfs(n,k);if (cnt==(1<<k)) return true; else return false;}int main() {int n,m,i,j,l,r,mid,ans;scanf("%d",&n);for (i=1;i<=n;i++) {cin >> a[i][0];a[i][1]=a[i][0];lc[i]=rc[i]=0;len[i]=a[i][0].length();}scanf("%d",&m);for (i=n+1;i<=n+m;i++) {scanf("%d%d",&lc[i],&rc[i]);a[i][0]=a[lc[i]][0];if (len[lc[i]]<=100) {a[i][0]=a[i][0]+a[rc[i]][0];}if (a[i][0].length()>=100) a[i][0] = a[i][0].substr(0, 100);a[i][1]=a[rc[i]][1];if (len[rc[i]]<=100) {a[i][1]=a[lc[i]][1]+a[i][1];}if (a[i][1].length() >= 100) a[i][1] = a[i][1].substr(a[i][1].length() - 100, 100);l=0,r=100,ans=0;while (l<=r) {mid=(l+r)/2;if (check(mid,i)) ans=mid,l=mid+1; else r=mid-1;}printf("%d\n",ans);}//system("pause");return 0;}



阅读全文
0 0
原创粉丝点击