zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    软工实践个人总结
    实验 7:OpenDaylight 实验——Python 中的 REST API 调用(含选做)
    2020软工实践第二次结对作业
    mocha单元测试简单教程
    实验 6:OpenDaylight 实验——OpenDaylight 及 Postman实现流表下发
    实验 5:OpenFlow 协议分析和 OpenDaylight 安装
    实验 4:Open vSwitch 实验——Mininet 中使用 OVS 命令
    福州大学软件工程实践第一次个人编程作业
    实验 3:Mininet实验 —— 测量路径的损耗率
    实验 2:Mininet 实验——拓扑的命令脚本生成
  • 原文地址:https://www.cnblogs.com/yyf0309/p/7632808.html
Copyright © 2011-2022 走看看