hihoCoder #1320 : 压缩字符串 区间dp

/**
题目:hihoCoder #1320 : 压缩字符串
链接:https://hihocoder.com/problemset/problem/1320
描述
小Hi希望压缩一个只包含大写字母‘A‘-‘Z‘的字符串。他使用的方法是:如果某个子串 S 连续出现了 X 次,就用‘X(S)‘来表示。
例如AAAAAAAAAABABABCCD可以用10(A)2(BA)B2(C)D表示。
此外,这种压缩方法是可以嵌套的,例如HIHOHIHOCODERHIHOHIHOCODER可以表示成2(2(HIHO)CODER)。
对于一个字符串 S ,合法的压缩表示可能有很多种。例如AAAAAAAAAABABABCCD还可以表示成9(A)3(AB)CCD。
小Hi希望知道其中最短的表示方法长度是多少。
输入
第一行一个正整数 T (1 ≤ T ≤ 10),表示测试数据的组数。
以下 T 行每行一个字符串 S ,长度不超过100。
输出
对于每组数据,输出最短的表示方法的长度。

思路:区间dp,定义dp[i][j]表示区间[i,j]压缩最小长度。
终止条件,容易推得长度<=4的区间最短长度就是区间长度。
如果长度>4.那么如果当前字符串是周期字符串,那么显然是可以合并越多越好,即:如果全部都是相同的,那么就全部合并起来。
所以从区间长度的约数由小到大找满足的周期。然后合并。
如果找不到,那么切割成两部分。

*/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<map>
#include<vector>
#include<queue>
#include<cctype>
#include<set>
#include<cstring>
#include<cmath>
using namespace std;
typedef pair<int,int> P;
typedef long long LL;
const int N = 104;
const int mod = 1000000007;
const int INF = 0x3f3f3f3f;
int dp[N][N];
char s[N];
vector<int> v[N];
void init()
{
    for(int i = 5; i < N; i++){
        for(int j = 1; j < i; j++){
            if(i%j==0){
                v[i].push_back(j);
            }
        }
    }
}
bool cmp(int l,int r,int l2,int r2)
{
    for(int i = l, j = l2; i < r; i++, j++){
        if(s[i]!=s[j]) return false;
    }
    return true;
}
int getLen(int x)
{
    int cnt = 0;
    while(x){
        x/=10; cnt++;
    }
    return cnt;
}
int dfs(int l,int r)
{
    if(r-l+1<=4) return r-l+1;
    int &res = dp[l][r];
    if(~res) return res;
    int len = r-l+1;
    int n = v[len].size();
    for(int i = 0; i < n; i++){///划分段数
        int d = v[len][i];     ///S = [l,l+d);
        int j;
        for(j = l+d; j <= r; j+=d){///T = [l+d,l+2d);
            if(cmp(l,l+d,j,j+d)==false) break;///不匹配。
        }
        if(j>r){
            return res = getLen(len/d)+2+dfs(l,l+d-1);
        }
    }
    res = INF;
    for(int i = l; i < r; i++){
        res = min(res,dfs(l,i)+dfs(i+1,r));
    }
    return res;
}
int main()
{
    int T;
    init();
    cin>>T;
    while(T--)
    {
        scanf("%s",s);
        memset(dp, -1, sizeof dp);
        printf("%d\n",dfs(0,strlen(s)-1));
    }
    return 0;
}
时间: 2024-10-01 04:31:04

hihoCoder #1320 : 压缩字符串 区间dp的相关文章

hihocoder 1320 压缩字符串(字符串+dp)

题解: 其实就是对应三种dp的转移方式 1.拼接类型 dp[i][j] = dp[i][c] + dp[c][j] 2.不变类型 dp[i][j] = j-i+1 3.重复类型(必须满足有k个循环节) dp[i][j] = width(k) + 2 + dp[i][i+L-1] 直接记忆化搜索即可,复杂度n^3logn(枚举循环节近似为logn) #include <iostream> #include <cstdio> #include <cstring> using

hihocoder 1320 - 压缩字符串 - [hiho一下160周]

这道题目可以说是一道非常好非常一颗赛艇的DP题了. 需要注意的是,其中情形3),字符串必然能完全转化为 N(str)形式,如果有N(str1)M(str2)等等另外样式,应该首先使用拼接形式对其进行划分. 那么,我们首先考虑写一个用来压缩情形3)下的字符串的函数zip(): 1 char str[105]; 2 int bit(int n) 3 { 4 int cnt=0; 5 while(n>0) 6 { 7 n/=10; 8 cnt++; 9 } 10 return cnt; 11 } 12

字符串折叠&amp;压缩(区间DP)

字符串折叠 题目描述 折叠的定义如下: 一个字符串可以看成它自身的折叠.记作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的最短折叠为:9(A)3(AB)CCD. 输

[BZOJ 1068] [SCOI2007] 压缩 【区间 DP 】

题目链接:BZOJ - 1068 题目分析 这种区间 DP 之前就做过类似的,也是字符串压缩问题,不过这道题稍微复杂一些. 需要注意如果某一段是 S1S1 重复,那么可以变成 M + Solve(S1) + R ,不过这个 Solve(S1) 中不能在中间有 M ,否则后面的 R 向前找到的 M 就不再是开头的 M 了. 代码 #include <iostream> #include <cstdio> #include <cstring> #include <al

bzoj 1068: [SCOI2007]压缩【区间dp】

神区间dp 设f[l][r][0]为在l到r中压缩的第一个字符为M,并且区间内只有这一个M,f[l][r][0]为在l到r中压缩的第一个字符为M,并且区间内有两个及以上的M 然后显然的转移是f[i][j][1]=min(f[i][k][0],f[i][k][1])+min(f[k+1][j][0],f[k+1][j][1])+1,f[i][j][0]=f[i][j][0],f[i][k][0]+j-k 然后考虑合并串,也就是当(l,mid),(mid+1,r)的串相等的时候,转移f[i][j][

UVA 4394 - String painter(字符串区间DP)

String painter                           Time Limit:3000MS    Memory Limit:0KB    64bit IO Format:%lld & %llu Description There are two strings A and B with equal length. Both strings are made up of lower case letters. Now you have a powerful string

UVa11584Partitioning by Palindromes(字符串区间dp)

题意:给定一个字符串s, 问说最少可以划分成几个回文串. 思路:dp[i]表示从1到第i个字符最少可以划分为几个回文,状态转移方程 dp[i] = min(dp[i], dp[j-1]+1),  如果满足 s[j] 到 s[i] 为回文字符串. 用 judge 函数判断从j到i是否可以形成回文串. Sample Input 3 racecar fastcar aaadbccb Sample Output 1 7 3 <span style="font-size:18px;">

【BZOJ-1068】压缩 区间DP

1068: [SCOI2007]压缩 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 1001  Solved: 615[Submit][Status][Discuss] Description 给一个由小写字母组成的字符串,我们可以用一种简单的方法来压缩其中的重复信息.压缩后的字符串除了小写字母外还可以(但不必)包含大写字母R与M,其中M标记重复串的开始,R重复从上一个M(如果当前位置左边没有M,则从串的开始算起)开始的解压结果(称为缓冲串). b

B1068 [SCOI2007]压缩 区间dp

这个题我状态想对了,但是转移错了...dp的代码难度都不大,但是思考含量太高了..不会啊,我太菜了. 其实这个题就是一个正常的区间dp,中间多了一个特判的转移就行了. 题干: Description 给一个由小写字母组成的字符串,我们可以用一种简单的方法来压缩其中的重复信息.压缩后的字符串除了小 写字母外还可以(但不必)包含大写字母R与M,其中M标记重复串的开始,R重复从上一个M(如果当前位置左边没 有M,则从串的开始算起)开始的解压结果(称为缓冲串). bcdcdcdcd可以压缩为bMcdRR