P4302 [SCOI2003]字符串折叠

题目描述

折叠的定义如下:

  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 }

原文地址:https://www.cnblogs.com/five20/p/9095505.html

时间: 2024-10-08 22:10:38

P4302 [SCOI2003]字符串折叠的相关文章

[SCOI2003]字符串折叠(区间dp)

P4302 [SCOI2003]字符串折叠 题目描述 折叠的定义如下: 一个字符串可以看成它自身的折叠.记作S = S X(S)是X(X>1)个S连接在一起的串的折叠.记作X(S) = SSSS-S(X个S). 如果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的最短折叠为

BZOJ 1090: [SCOI2003]字符串折叠( 区间dp )

按照题意dp...dp(l, r) = min{ dp(l, x) + dp(x+1, r) , 折叠(l, r) } 折叠(l, r)我是直接枚举长度然后哈希判.. -------------------------------------------------------------- #include<bits/stdc++.h> using namespace std; typedef unsigned long long ull; const int maxn = 109; con

bzoj 1090 [SCOI2003]字符串折叠(区间DP)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1090 [题意] 给定一个字符串,问将字符串折叠后的最小长度. [思路] 设f[i][j]表示将区间ij折叠后的最小长度,则有转移式: f[i][j]=min{ j-i+1,f[i][k]+f[k+1][j],f[i][i+x-1]+2+digit((j-i+1)/x) } 第一项代表不折叠,第二项代表当前不折叠,第三项代表以x长度折叠ij区间,条件是满足ij区间以x为循环节. [代码

BZOJ1090: [SCOI2003]字符串折叠

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1090 Description 折叠的定义如下: 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)?AAACAA

【BZOJ 1090】[SCOI2003]字符串折叠

Description 折 叠的定义如下: 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

【BZOJ】1090: [SCOI2003]字符串折叠(dp)

http://www.lydsy.com/JudgeOnline/problem.php?id=1090 随便yy一下.. 设f[i,j]表示i-j的最小长度 f[i, j]=min{j-i+1, f[i,k]+f[k+1, j], count[x]+2+f[i, i+x-1]},其中count[x]表示x的位数,最后边的转移那个条件是i~j都是长度为x的串连在一起. 然后最后那个转移暴力233可以水过... #include <cstdio> #include <cstring>

BZOJ 1090 SCOI2003 字符串折叠 动态规划+Hash

题目大意:给定一个字符串,求按照题中所给的压缩方式最短能压缩到多长 区间DP 令f[i][j]表示[i,j]区间内的字符串最短能压缩到多长 普通的区间DP:f[i][j]=min{f[i][k]+f[k+1][j]} (i<=k<=j-1) 此外如果对这段字符串进行压缩,那么我们可以枚举循环节,用Hash来判断 如果k是一个循环节,那么有f[i][j]=min(f[i][j],f[i][i+k-1]+digit[len/k]+2) 其中len=j-i+1,digit表示一个数在十进制下的长度

bzoj1090:[SCOI2003]字符串折叠

思路:区间dp,令f[l][r]表示l到r的答案,于是f[l][r]=min(f[l][mid],f[mid+1][r]),如果能折叠f[l][r]=min(f[l][r],f[l][l+len-1]+calc(r-l+1,len),calc是计算数字的长度.记忆化搜索即可. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include

[SCOI2003] 字符串折叠

link 其实一眼看到就能想到区间$dp$吧 设$dp(i,j)$表示从$i$到$j$的折叠次数最小,我们每次确定一个数$k$,若$i$~$k$能匹配$k+1$~$j$那么$dp(i,j)=dp(i,k)+2+s$,$s$为括号左面的数字的位数,$+2$是因为要算上括号,若不能则$dp(i,j)=dp(i,k)+dp(k+1,j)$ 代码NOIP考完在发吧 原文地址:https://www.cnblogs.com/si-rui-yang/p/9876400.html