1. 程式人生 > >P4302 [SCOI2003]字符串折疊

P4302 [SCOI2003]字符串折疊

strings for put 斷點 考試 lock -m sss AS

題目描述

折疊的定義如下:

  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。

輸出格式:

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

輸入輸出樣例

輸入樣例#1:
NEERCYESYESYESNEERCYESYESYES
輸出樣例#1:
14

說明

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

Solution:

  本題考試時沒搞出來。(話說老余$AK$了!,自己還是個蒟蒻‘!`~`!`)

  就是一個區間$DP$,我這裏用記憶化搜索來實現。

  巧妙運用一下字符串$string$類型。定義狀態$f[i][j]$表示區間$[i,j]$折疊後的最短字符串,那麽當$l==r$時,顯然$f[l][r]==s[l]$,搜索時枚舉斷點遞歸,找到使原串折疊後的長度最短的斷點,然後枚舉折疊的長度,這裏用到了$stringstream$(字符串輸入輸出流)定義中間變量$op$,這樣就可以簡單的進行字符串的賦值,每一次$f[l][r]$賦為$f[l][r],op$中長度最短的一個(代碼中的$op.tellp()$返回的是當前$put$流指針的位置(類似的還有$tellg$,返回$get$流指針的位置),可以理解為$op$的尾指針位置,即它的長度)。

  這樣寫的好處是簡潔而且能簡單輸出折疊後的字符串(一模一樣的題,只是輸出的是字符串,洛谷搜:$UVA1630\;Folding$,$STL$大法好!)。

  此時先為不會$stringstream$的小夥伴們,安利一波(我測試的代碼):

 1 #include<iostream>
 2 #include<sstream>  //stringstream所需的頭文件
 3 using namespace std;
 4 int main(){
 5     ios::sync_with_stdio(0);  //取消流同步是可以用的,完全和string輸入輸出流無關
6 7 stringstream op; //定義string輸入輸出流,任意變量和string互轉 8 string p; 9 char s[12]={"lalalavan"}; 10 op<<s; //將char類型的字符串賦值給op 11 op>>p; //將op輸出到p中 12 cout<<op.str()<<endl<<p<<endl; //兩種輸出方式 13 14 op.str(""); 15 op.clear(); //對op清空必須兩個都要用,可以自行嘗試去掉一個,會出兮兮`~` 16 17 string num="23333"; 18 int n; 19 op<<num;op>>n; //將string類型轉為int類型 20 cout<<n<<endl; //輸出轉換後的int類型 21 return 0; 22 }

本題代碼:

 1 #include<bits/stdc++.h>
 2 #define il inline
 3 #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
 4 #define Min(a,b) ((a)>(b)?(b):(a))
 5 #define INF 23333
 6 using namespace std;
 7 int n;
 8 string s,f[105][105];
 9 il int check(int l,int r){
10     int sl=r-l+1;
11     For(k,1,sl>>1){
12         if(sl%k)continue;
13         bool f=1;
14         For(i,l,r-k){
15             if(s[i]==s[i+k])continue;
16             f=0;
17             break;
18         }
19         if(f)return k;
20     }
21     return 0;
22 }
23 il string dfs(int l,int r){
24     if(!f[l][r].empty())return f[l][r];
25     if(l==r)return f[l][r]=s[l];
26     int mink,ansl=INF;
27     For(i,l,r-1){
28         int len=dfs(l,i).size()+dfs(i+1,r).size();
29         if(len<ansl)mink=i,ansl=len;
30     }
31     f[l][r]+=dfs(l,mink),f[l][r]+=dfs(mink+1,r);
32     int k=check(l,r);
33     if(k){
34         stringstream op;   //定義輸入輸出流
35         op<<(r-l+1)/k<<"("<<dfs(l,l+k-1)<<")";    //將後面一大串依次賦給op
36         if(op.tellp()<f[l][r].size()) op>>f[l][r];  //比較f[l][r]和op取長度最小的
37     }
38     return f[l][r];
39 }
40 int main(){
41     cin>>s;
42     n=s.size();
43     For(i,0,n-1) For(j,0,n-1)f[i][j].clear();
44     cout<<dfs(0,n-1).size();
45     return 0;
46 }

P4302 [SCOI2003]字符串折疊