[SCOI2003]字符串折叠
Solution
这种字符串题一般都是区间 dp,设
若有折叠操作,这时想要折叠就必须满足整段是一个循环,所以我们枚举循环节长度,用 hash 判断是否是循环节,若是,则转移方程如下:
其中加
补充
hash 判循环节的方式如下:
如图,
此算法判断一个段是否为循环节是
Code
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
using namespace std;
void read(int &x)
{
char ch=getchar();
int r=0,w=1;
while(!isdigit(ch))w=ch=='-'?-1:1,ch=getchar();
while(isdigit(ch))r=(r<<3)+(r<<1)+(ch^48),ch=getchar();
x=r*w;
}
const int N=107,K=133;
char c[N];
int f[N][N],t[N];
ull g[N],p[N];
void init()
{
p[0]=1;
for(int i=1;i<=105;i++)
p[i]=p[i-1]*K;
}
void Get(char *s,int n)
{
for(int i=1;i<=n;i++)
g[i]=g[i-1]*K+s[i];
}
int gethash(int l,int r)
{return g[r]-g[l-1]*p[r-l+1];}
main()
{
scanf("%s",c+1);
int n=strlen(c+1);
init();Get(c,n);
memset(f,63,sizeof f);
for(int i=1;i<=9;i++)t[i]=1;
for(int i=10;i<=99;i++)t[i]=2;
t[100]=3;
for(int i=1;i<=n;i++)f[i][i]=1;
for(int len=2;len<=n;len++)
for(int i=1;i<=n-len+1;i++)
{
int j=i+len-1;
for(int k=i;k<j;k++)
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
for(int k=i;k<j;k++)
{
int l=k-i+1;
if(len%l!=0)continue;
if(gethash(i,j-l)==gethash(i+l,j))
f[i][j]=min(f[i][j],f[i][k]+2+t[len/l]);
}
}
cout<<f[1][n];
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】