zoukankan      html  css  js  c++  java
  • 【洛谷P4302】字符串折叠

    题目

    题目链接:https://www.luogu.com.cn/problem/P4302
    折叠的定义如下:

    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。

    思路

    \(f[i][j]\) 表示 \([i,j]\) 这一段的最小折叠。那么 \(f[i][j]\) 可能会有两种转移:

    1. 枚举一个中间点 \(k\)\(f[i][j]=\min(f[i][k]+f[k+1][j])\)
    2. 枚举一个中间点 \(k\)\([i\sim k]\) 正好是 \((k\sim j]\) 的前缀,且可以经过若干次自我复制得到 \((k\sim j]\)

    对于第二个转移,我们需要在较优秀复杂度内判断一段区间是否是另一段区间前缀且可以自我复制变成另一段区间。用字符串 hash 乱搞即可。
    时间复杂度 \(O(n^3)\)

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef unsigned long long ull;
    
    const int N=110;
    const ull base=131;
    int n,f[N][N],cnt[N];
    ull power,g[N][N],hash[N][N];
    char ch[N];
    
    int main()
    {
    	scanf("%s",ch+1);
    	n=strlen(ch+1);
    	memset(f,0x3f3f3f3f,sizeof(f));
    	power=1;
    	for (int i=1;i<=n;i++)
    	{
    		cnt[i]=cnt[i/10]+1;
    		g[i][1]=1; power=power*base;
    		for (int j=i*2;j<=n;j+=i)
    			g[i][j/i]=g[i][j/i-1]*power+1ULL;
    		f[i][i]=1;
    	}
    	for (int i=1;i<=n;i++)
    		for (int j=i;j<=n;j++)
    			hash[i][j]=hash[i][j-1]*base+ch[j];
    	for (int i=n;i>=1;i--)
    		for (int j=i+1;j<=n;j++)
    			for (int k=i;k<j;k++)
    			{
    				f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
    				int len1=k-i+1,len2=j-k;
    				if (len2%len1==0 && hash[i][k]*g[len1][len2/len1]==hash[k+1][j])
    					f[i][j]=min(f[i][j],f[i][k]+2+cnt[len2/len1+1]);
    			}
    	printf("%d",f[1][n]);
    	return 0;
    }
    
  • 相关阅读:
    Linux双线双网卡双IP双网关设置方法
    Docker 清理命令集锦
    Centos7安装Docker 基于Dockerfile 搭建httpd运行环境
    Centos6.x 安装vnc
    KVM虚拟化技术
    ELK监控系统nginx / mysql慢日志
    ELK初学搭建(elasticsearch)
    (转)Linux 磁盘IO性能测试
    hadoop2.9.2 调整jvm
    (转)shell调试方法
  • 原文地址:https://www.cnblogs.com/stoorz/p/13790336.html
Copyright © 2011-2022 走看看