zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 41 (Rated for Div. 2) F. k-substrings

    F. k-substrings
    time limit per test
    4 seconds
    memory limit per test
    256 megabytes
    input
    standard input
    output
    standard output

    You are given a string s consisting of n lowercase Latin letters.

    Let's denote k-substring of s as a string subsk = sksk + 1..sn + 1 - k. Obviously, subs1 = s, and there are exactly  such substrings.

    Let's call some string t an odd proper suprefix of a string T iff the following conditions are met:

    • |T| > |t|;
    • |t| is an odd number;
    • t is simultaneously a prefix and a suffix of T.

    For evey k-substring () of s you have to calculate the maximum length of its odd proper suprefix.

    Input

    The first line contains one integer n (2 ≤ n ≤ 106) — the length s.

    The second line contains the string s consisting of n lowercase Latin letters.

    Output

    Print  integers. i-th of them should be equal to maximum length of an odd proper suprefix of i-substring of s (or  - 1, if there is no such string that is an odd proper suprefix of i-substring).

    Examples
    input
    Copy
    15
    bcabcabcabcabca
    output
    Copy
    9 7 5 3 1 -1 -1 -1
    input
    Copy
    24
    abaaabaaaabaaabaaaabaaab
    output
    Copy
    15 13 11 9 7 5 3 1 1 -1 -1 1
    input
    Copy
    19
    cabcabbcabcabbcabca
    output
    Copy
    5 3 1 -1 -1 1 1 -1 -1 -1
    Note

    The answer for first sample test is folowing:

    • 1-substring: bcabcabcabcabca
    • 2-substring: cabcabcabcabc
    • 3-substring: abcabcabcab
    • 4-substring: bcabcabca
    • 5-substring: cabcabc
    • 6-substring: abcab
    • 7-substring: bca
    • 8-substring: c

    思路一:考虑用hash值判断字符串等价性。对于每个查询点,我们正常二分长度是不满足单调性的;于是我们转换思路,不对单点二分,而是对于每个固定的答案中心点,因为其对称的另外的点是固定的,因此可以二分求出最大匹配长度,如对于mi,最大匹配长度是2 * x + 1,则更新ans[mi - x] = max(ans[mi - x], 2 * x + 1)。这样枚举完中间点之后,我们并没有做完,因为我们只更新了每个中心点最大匹配长度对应的起点的答案,但相同的中心点,也可能作为其他起点取到最大值的中心点,因此对于每个ans[i],先将其赋为max(ans[i], ans[i - 1] - 2)。这样扫一遍ans数组就行了。瓶颈在于预处理,nlogn。

     1 #include <iostream>
     2 #include <fstream>
     3 #include <sstream>
     4 #include <cstdlib>
     5 #include <cstdio>
     6 #include <cmath>
     7 #include <string>
     8 #include <cstring>
     9 #include <algorithm>
    10 #include <queue>
    11 #include <stack>
    12 #include <vector>
    13 #include <set>
    14 #include <map>
    15 #include <list>
    16 #include <iomanip>
    17 #include <cctype>
    18 #include <cassert>
    19 #include <bitset>
    20 #include <ctime>
    21 
    22 using namespace std;
    23 
    24 #define pau system("pause")
    25 #define ll long long
    26 #define pii pair<int, int>
    27 #define pb push_back
    28 #define mp make_pair
    29 #define clr(a, x) memset(a, x, sizeof(a))
    30 
    31 const double pi = acos(-1.0);
    32 const int INF = 0x3f3f3f3f;
    33 const int MOD = 1e9 + 7;
    34 const double EPS = 1e-9;
    35 const int B = 131;
    36 
    37 int n;
    38 char s[1000015];
    39 ll Hash[1000015], pp[1000015];
    40 ll get_Hash(int s, int e) {
    41     ll res = (Hash[e] - pp[e - s + 1] * Hash[s - 1]) % MOD;
    42     if (res < 0) res += MOD;
    43     return res;
    44 }
    45 int ans[1000015];
    46 bool check(int mi, int x) {
    47     return get_Hash(mi - x + 1, mi + x - 1) == get_Hash(n + 1 - mi - x + 1, n + 1 - mi + x - 1);
    48 }
    49 int main() {
    50     scanf("%d %s", &n, s + 1);
    51     pp[0] = 1;
    52     for (int i = 1; i <= n; ++i) {
    53         Hash[i] = (Hash[i - 1] * B + s[i]) % MOD;
    54         pp[i] = pp[i - 1] * B % MOD;
    55     }
    56     clr(ans, -1);
    57     for (int i = 1; i <= n + 1 >> 1; ++i) {
    58         int s = 1, e = i, mi, res = 0;
    59         if (2 * i == n + 1) break;
    60         while (s <= e) {
    61             mi = s + e >> 1;
    62             if (check(i, mi)) s = (res = mi) + 1;
    63             else e = mi - 1;
    64         }
    65         ans[i - res + 1] = max(ans[i - res + 1], 2 * res - 1);
    66     }
    67     for (int i = 1; i <= n + 1 >> 1; ++i) {
    68         ans[i] = max(ans[i - 1] - 2, ans[i]);
    69         printf("%d ", ans[i]);
    70     }
    71     return 0;
    72 }
    View Code

    思路二:我们注意到性质ans[i] >= ans[i - 1] + 2, 也就是ans[i - 1] <= ans[i] - 2.因此我们从后往前扫ans数组,每个点从ans[i] - 2暴力向下枚举,找到答案就是最终解,并马上break。这样总体的步幅顶多n + 2 * n。复杂度O(n)。

     1 #include <iostream>
     2 #include <fstream>
     3 #include <sstream>
     4 #include <cstdlib>
     5 #include <cstdio>
     6 #include <cmath>
     7 #include <string>
     8 #include <cstring>
     9 #include <algorithm>
    10 #include <queue>
    11 #include <stack>
    12 #include <vector>
    13 #include <set>
    14 #include <map>
    15 #include <list>
    16 #include <iomanip>
    17 #include <cctype>
    18 #include <cassert>
    19 #include <bitset>
    20 #include <ctime>
    21 
    22 using namespace std;
    23 
    24 #define pau system("pause")
    25 #define ll long long
    26 #define pii pair<int, int>
    27 #define pb push_back
    28 #define mp make_pair
    29 #define clr(a, x) memset(a, x, sizeof(a))
    30 
    31 const double pi = acos(-1.0);
    32 const int INF = 0x3f3f3f3f;
    33 const int MOD = 1e9 + 7;
    34 const double EPS = 1e-9;
    35 const int B = 131;
    36 
    37 int n;
    38 char s[1000015];
    39 ll Hash[1000015], pp[1000015];
    40 ll get_Hash(int s, int e) {
    41     ll res = (Hash[e] - pp[e - s + 1] * Hash[s - 1]) % MOD;
    42     if (res < 0) res += MOD;
    43     return res;
    44 }
    45 int ans[1000015];
    46 bool check(int mi, int x) {
    47     return get_Hash(mi - x + 1, mi + x - 1) == get_Hash(n + 1 - mi - x + 1, n + 1 - mi + x - 1);
    48 }
    49 int main() {
    50     scanf("%d %s", &n, s + 1);
    51     pp[0] = 1;
    52     for (int i = 1; i <= n; ++i) {
    53         Hash[i] = (Hash[i - 1] * B + s[i]) % MOD;
    54         pp[i] = pp[i - 1] * B % MOD;
    55     }
    56     clr(ans, -1);
    57     for (int i = n + 1 >> 1; i; --i) {
    58         int l = i, r = n + 1 - i;
    59         if (l == r) {
    60             ans[i] = -1;
    61             continue;
    62         }
    63         for (int j = ans[i + 1] + 2; ~j; j -= 2) {
    64             if (get_Hash(l, l + j - 1) == get_Hash(r - j + 1, r)) {
    65                 ans[i] = j;
    66                 break;
    67             }
    68         }
    69     }
    70     for (int i = 1; i <= n + 1 >> 1; ++i) {
    71         printf("%d ", ans[i]);
    72     }
    73     return 0;
    74 }
    View Code
  • 相关阅读:
    Exp7 网络欺诈防范
    Exp6 信息搜集与漏洞扫描
    Exp4 恶意代码分析
    Exp2 后门原理与实践
    PC平台逆向破解实验报告
    See You Again——我最后的汇编程序
    表格标签
    ansible环境搭建
    OSPF_1
    Linux的文件管理(8-27)
  • 原文地址:https://www.cnblogs.com/BIGTOM/p/9146337.html
Copyright © 2011-2022 走看看