• [BZOJ1090/Luogu4302][SCOI2003]字符串折叠


    题目链接:

    BZOJ1090

    Luogu4302

    一个简单的区间(DP)

    (f_{[l][r]})表示子串(lsim r)的最小长度,那么显然的有以下转移:

    [f_{[l][r]}=r-l+1 ]

    什么都不做,长度不变。

    [f_{[l][r]}=min_{i=l}^{r-1}limits{f_{[l][i]}+f_{[i+1][r]}} ]

    枚举端点,由两个子串拼接而成。

    [f_{[l][r]}=Length(c)+2+f_{[l][l+c-1]} ]

    其中(Length(x))表示(x)的位数,(c)表示区间(lsim r)内的最短循环节。(2)表示两个括号。

    (c)怎么求?暴力即可。

    应该有更快的方法,字符串算法瞎搞搞

    时间复杂度?(O(n^3log_2n))?(不太会算

    #include <cstdio>
    #include <cstring>
    
    inline int Min(int a,int b){return a<b?a:b;}
    
    int f[105][105];
    char s[105];
    
    inline int Length(int x)//x的位数
    {
    	return x>9?Length(x/10)+1:1;
    }
    
    inline bool Equal(int a,int b,int l)//判断以a,b为左端的两个长度为l的字符串是否相等
    {
    	for(int i=1;i<=l;++i,++a,++b)
    		if(s[a]!=s[b])return false;
    	return true;
    }
    
    inline int MinFor(int l,int r)//求[l,r]的最小循环节
    {
    	for(int i=1;i<=(r-l+1);++i)
    		if((r-l+1)%i==0)//枚举因子
    		{
    			bool Flag=true;
    			for(int j=l;j+i<=r;j+=i)
    				if(!Equal(j,j+i,i))
    					Flag=false,j=r;
    			if(Flag)return i;
    		}
    	return 0;
    }
    
    int DP(int l,int r)
    {
    	if(l>r)return 0;//递归边界
    	if(f[l][r])return f[l][r];
    	f[l][r]=r-l+1;
    	int Fors=MinFor(l,r);
    	f[l][r]=Min(f[l][r],Length((r-l+1)/Fors)+2+DP(l,l+Fors-1));
    	for(int i=l;i<r;++i)
    		f[l][r]=Min(f[l][r],DP(l,i)+DP(i+1,r));
    	return f[l][r];
    }
    
    int main()
    {
    	scanf("%s",s+1);
    	printf("%d
    ",DP(1,strlen(s+1)));
    	return 0;
    }
    
  • 相关阅读:
    php工作笔记5-css定位
    php工作笔记4-mysql笔记1
    php工作笔记3-php基础加强
    php工作笔记2-php编码效率
    php工作笔记1-数组常用方法总结,二维数组的去重,上传图片到oss服务器
    android浏览器 源码共享
    违章查询源码分享
    CENTOS 6.5 配置YUM安装NGINX
    Linux下安装Oracle11g服务器
    ARCGIS SDE空间化处理
  • 原文地址:https://www.cnblogs.com/LanrTabe/p/10187653.html
Copyright © 2020-2023  润新知