zoukankan      html  css  js  c++  java
  • 搜索/动规-字符串折叠

    找循环节时可以用 KMP 优化一下,但是 100 的数据嘛当然是选择暴力出奇迹呀。

    Update:

    2018/03/17 做另外一道类似的题时又想到了这道题,我的代码里每次 dfs(L, R) 都做了一次 KMP,非常笨。

    可以预处理一下(求出 [L, R] 的 fail 数组后, [L, L+1], [L, L+2], ... , [L, R] 这些区间的循环节都可以得到)。

    只需要求 [1, N], [2, N], [3, N], ..., [N, N] 的 fail 数组就行了,这个预处理过程是 O(N^2) 的。

    总结一下吧。最近做到了这样一类 DP 题,它们的方程在转移时候用到的东西需要预处理。而预处理过程

    往往涉及一些算法——

    可能是 DP (IOI 2000 邮局问题,NKOJ1181),可能是前缀和,可能是 KMP 。

     1 #include <stdio.h> 
     2 #include <string.h> 
     3 #include <algorithm> 
     4 
     5 int len; 
     6 int Mem[120][120], fail[120]; 
     7 char S[120]; 
     8 
     9 inline int Bitcnt(int v) 
    10 { 
    11     int cnt = 0; 
    12     do ++cnt; 
    13     while (v /= 10); 
    14     return cnt; 
    15 } 
    16 
    17 int dfs(int L, int R) 
    18 { 
    19     if (Mem[L][R]) return Mem[L][R]; 
    20     if (L == R) return Mem[L][R] = 1; 
    21      
    22     int i, j; 
    23     Mem[L][R] = R - L + 1; 
    24      
    25     //KMP 
    26     char *tmp_S = S + L - 1;
    27     int tmp_len = R - L + 1; 
    28     fail[1] = j = 0; 
    29     for (i = 2; i <= tmp_len; ++i) { 
    30         while (j && tmp_S[j + 1] != tmp_S[i]) 
    31             j = fail[j]; 
    32         if (tmp_S[j + 1] == tmp_S[i]) ++j; 
    33         fail[i] = j; 
    34     } 
    35     int tmp_cut = tmp_len - fail[tmp_len]; 
    36     if (tmp_len != tmp_cut && !(tmp_len % tmp_cut)) 
    37         Mem[L][R] = std::min(Mem[L][R], Bitcnt(tmp_len / tmp_cut) + 2 + dfs(L, L + tmp_cut - 1)); 
    38      
    39     for (i = L; i < R; ++i) 
    40         Mem[L][R] = std::min(Mem[L][R], dfs(L, i) + dfs(i+1, R)); 
    41      
    42     return Mem[L][R]; 
    43 } 
    44 
    45 int main() 
    46 { 
    47     scanf("%s", S + 1); 
    48     len = strlen(S + 1); 
    49     printf("%d
    ", dfs(1, len)); 
    50     return 0; 
    51 }
    View Code

    NKOJ2388

    字符串折叠
    时间限制 : 10009 MS   空间限制 : 65536 KB
    问题描述

    折叠的定义如下:
    1. 一个字符串可以看成它自身的折叠。记作S =S
    2. X(S)是X(X>1)个S连接在一起的串的折叠。记作X(S) = SSSS…S(X个S)。
    3. 如果A = A’, B=B’,则AB = A’B’
    例如,因为3(A) = AAA, 2(B) = BB,所以3(A)C2(B) = AAACBB,而2(3(A)C)2(B)=AAACAAACBB给一个字符串,求它的最短折叠。
    例如AAAAAAAAAABABABCCD的最短折叠为:9(A)3(AB)CCD。

    输入格式

    仅一行,即字符串S,长度保证不超过100。

    输出格式

    仅一行,即最短的折叠长度

    样例输入

    NEERCYESYESYESNEERCYESYESYES

    样例输出

    14

  • 相关阅读:
    TC配置文件WCMD.INI详解,只能在ini重修改的配置
    Source Insight中的多行注释
    ACE_Timer_Heap_T定时器
    什么是代理服务器
    太阳能传感器目前主要故障问题解决方案
    source insight中文显示和处理
    C#3.0新特性小结(2)
    .NET中事务操作小结(1)
    常用的正则表达式收藏版
    几种流行的Ajax开发框架比较
  • 原文地址:https://www.cnblogs.com/ghcred/p/8544648.html
Copyright © 2011-2022 走看看