1. 程式人生 > >[Luogu P4302] [BZOJ 1090] [SCOI2003]字串摺疊

[Luogu P4302] [BZOJ 1090] [SCOI2003]字串摺疊

洛谷傳送門

題目描述

摺疊的定義如下:

  1. 一個字串可以看成它自身的摺疊。記作S=SS = S

  2. X(S)X(S)X(X>1)X(X>1)SS連線在一起的串的摺疊。記作X(S)=SSSSS(XS)X(S) = SSSS…S(X個S)

  3. 如果A=A,B=BA = A’, B = B’,則AB=ABAB = A’B’ 例如,因為3(A)=AAA,2(B)=BB3(A) = AAA, 2(B) = BB,所以3(A)C2

    (B)=AAACBB3(A)C2(B) = AAACBB,而2(3(A)C)2(B)=AAACAAACBB2(3(A)C)2(B) = AAACAAACBB

    給一個字串,求它的最短折疊。例如AAAAAAAAAABABABCCDAAAAAAAAAABABABCCD的最短折疊為:9(A)3(AB)CCD9(A)3(AB)CCD

輸入輸出格式

輸入格式:

僅一行,即字串SS,長度保證不超過100100

輸出格式:

僅一行,即最短的摺疊長度。

輸入輸出樣例

輸入樣例#1:

NEERCYESYESYESNEERCYESYESYES

輸出樣例#1:

14

說明

一個最短的摺疊為:2(NEERC3(YES))2(NEERC3(YES))

解題分析

區間dpdp, 大力判是否相同再轉移即可。

複雜度? 似乎是卡不滿的O(N4)O(N^4)

程式碼如下:

#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#define R register #define IN inline #define W while #define gc getchar() #define MX 105 int dp[MX][MX]; char buf[MX]; int len, ans; IN bool judge(R int x1, R int y1, R int x2, R int y2) { if(y1 - x1 > y2 - x2) return false; if((y2 - x1 + 1) % (y1 - x1 + 1)) return false; int len = y1 - x1 + 1; for (R int i = x2; i <= y2; ++i) if(buf[i] ^ buf[i - len]) return false; return true; } IN int get (R int now) { R int ret = 0; W (now) ++ret, now /= 10; return ret; } int main(void) { scanf("%s", buf + 1); len = std::strlen(buf + 1); for (R int i = 1; i <= len; ++i) for (R int j = i; j <= len; ++j) dp[i][j] = j - i + 1; for (R int i = 1; i < len; ++i) { for (R int j = 1; j <= len - i; ++j) { for (R int k = j; k < j + i; ++k) { if(!judge(j, k, k + 1, j + i)) dp[j][j + i] = std::min(dp[j][j + i], dp[j][k] + dp[k + 1][j + i]); else dp[j][j + i] = std::min(dp[j][j + i], dp[j][k] + get((i + 1) / (k - j + 1)) + 2); } } } printf("%d", dp[1][len]); }