• 【BZOJ】1068: [SCOI2007]压缩(dp)


    http://www.lydsy.com/JudgeOnline/problem.php?id=1068

    发现如果只设一维的话无法转移

    那么我们开第二维,发现对于前i个来说,如果确定了M在哪里,第i个是用R还是不用就能确定了(如果用R那么在中间一定变成了缓冲串)

    那么可以转移了

    设d[i,j]表示前i个串,最近的一个M在i的前边一个格子,的最短长度,有

    d[1,1]=1

    d[i,i]=min{d[i-1,j]}+2 //即用一次M又补上i,所以+2

    d[i,j]=d[pos,j]+1,其中pos=(i+j-1)/2,且是整数(就是确定了M找前一个R),且s[j, pos]=s[pos+1, i]

    d[i,j]=min{d[i,j], d[k, j]+i-k}

    答案就是min{d[n,i], 1<=i<=n}

    因为数据小所以直接暴力处理,也就是n^3的,n^2的话应该挺好优化的

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <string>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <set>
    #include <map>
    using namespace std;
    typedef long long ll;
    #define pii pair<int, int>
    #define mkpii make_pair<int, int>
    #define pdi pair<double, int>
    #define mkpdi make_pair<double, int>
    #define pli pair<ll, int>
    #define mkpli make_pair<ll, int>
    #define rep(i, n) for(int i=0; i<(n); ++i)
    #define for1(i,a,n) for(int i=(a);i<=(n);++i)
    #define for2(i,a,n) for(int i=(a);i<(n);++i)
    #define for3(i,a,n) for(int i=(a);i>=(n);--i)
    #define for4(i,a,n) for(int i=(a);i>(n);--i)
    #define CC(i,a) memset(i,a,sizeof(i))
    #define read(a) a=getint()
    #define print(a) printf("%d", a)
    #define dbg(x) cout << (#x) << " = " << (x) << endl
    #define error(x) (!(x)?puts("error"):0)
    #define printarr2(a, b, c) for1(_, 1, b) { for1(__, 1, c) cout << a[_][__]; cout << endl; }
    #define printarr1(a, b) for1(_, 1, b) cout << a[_] << '	'; cout << endl
    inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }
    inline const int max(const int &a, const int &b) { return a>b?a:b; }
    inline const int min(const int &a, const int &b) { return a<b?a:b; }
    
    const int N=52, oo=0x3f3f3f3f;
    int d[N][N], n;
    char s[N];
    bool check(int i, int j) {
    	int pos=(i+j-1), k=1;
    	if(pos&1) return 0;
    	pos>>=1;
    	if(d[pos][j]>=oo) return 0;
    	for1(x, j, pos) { if(s[x]!=s[pos+k]) return 0; ++k; }
    	return 1;
    }
    int main() {
    	scanf("%s", s+1);
    	n=strlen(s+1);
    	CC(d, oo);
    	d[1][1]=1;
    	for1(i, 2, n) {
    		for1(j, 1, i-1) d[i][i]=min(d[i-1][j], d[i][i]);
    		d[i][i]+=2;
    		for1(j, 1, i-1) {
    			if(check(i, j)) d[i][j]=d[(i+j-1)>>1][j]+1;
    			for1(k, j, i-1) d[i][j]=min(d[i][j], d[k][j]+i-k);
    		}
    	}
    	int ans=oo;
    	for1(i, 1, n) ans=min(d[n][i], ans);
    	print(ans);
    	return 0;
    }
    

      


    Description

    给一个由小写字母组成的字符串,我们可以用一种简单的方法来压缩其中的重复信息。压缩后的字符串除了小写字母外还可以(但不必)包含大写字母R与M,其中M标记重复串的开始,R重复从上一个M(如果当前位置左边没有M,则从串的开始算起)开始的解压结果(称为缓冲串)。 bcdcdcdcd可以压缩为bMcdRR,下面是解压缩的过程:

     

    另一个例子是abcabcdabcabcdxyxyz可以被压缩为abcRdRMxyRz。

    Input

    输入仅一行,包含待压缩字符串,仅包含小写字母,长度为n。

    Output

    输出仅一行,即压缩后字符串的最短长度。

    Sample Input

    bcdcdcdcdxcdcdcdcd

    Sample Output

    12

    HINT

    在第一个例子中,解为aaaRa,在第二个例子中,解为bMcdRRxMcdRR。 

    【限制】 

    100%的数据满足:1<=n<=50 100%的数据满足:1<=n<=50

    Source

     
  • 相关阅读:
    控制器之间的通信(传值方法)以及多次调用通信
    关于ios项目沙盒中的文件和Xcode项目创建的文件
    解决cell循环利用造成的重复勾选
    让TabelView视图中自定义的Toolbar固定(不随cell的移动而移动)
    jsonString转NSDictionary
    日期字符串转换 and 两个日期相减
    Java虚拟机 简介
    浅谈操作系统对内存的管理(转)
    Java虚拟机规范(Java SE 7)笔记
    StringUtils
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/4110402.html
Copyright © 2020-2023  润新知