Description
文本压缩的算法有很多种,这里给出一种叫做PermRLE的压缩算法。定义一个整数k, PermRLE算法依赖于一种压缩顺序。所谓的压缩顺序就是一种1~
Input
输入第一行有一个整数
接下来一行有一个字符串,保证字符串的长度能被k整除,且字符串里仅含有小写字母。
1≤k≤16,1≤Len≤50000
Output
输出一行,仅包含文本压缩之后的最小长度。
Sample Input
4
abcabcabcabc
Sample Output
7
HINT
k的排列是1 4 3 2,然后原字符串变成aacbbbacccba,压缩之后变成acbacba,长度为7,可以证明,这是最小答案
思路
对于一个字符串,它总是能够分成
abcabcabcabc
分成块就是:
abca
bcab
cabc
那么inside1,4=3,inside1,3=0,between4,3=2。
对于k的一个排列,显然只需要关心那些数出现过,那些没有,设
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
const int maxn=16;
const int maxlen=60000;
int f[1<<maxn][maxn+1][maxn+1],ans;
int n,len,inside[maxn+1][maxn+1],between[maxn+1][maxn+1];
char s[maxlen+10];
int main()
{
scanf("%d%s",&n,s+1);
len=strlen(s+1);
for(int i=0; i<len/n; i++)
{
for(int j=1; j<=n; j++)
{
for(int k=1; k<=n; k++)
{
if(j!=k)
{
inside[j][k]+=s[i*n+j]==s[i*n+k];
}
}
}
}
for(int i=0; i<len/n-1; i++)
{
for(int j=1; j<=n; j++)
{
for(int k=1; k<=n; k++)
{
between[j][k]+=s[i*n+j]==s[(i+1)*n+k];
}
}
}
for(int i=0; i<1<<n; i++)
{
for(int j=1; j<=n; j++)
{
if(i&(1<<(j-1)))
{
for(int k=1; k<=n; k++)
{
if((j!=k)&&(i&(1<<(k-1))))
{
for(int l=1; l<=n; l++)
{
if(i&(1<<(l-1)))
{
if(k!=l)
{
f[i][j][k]=std::max(f[i][j][k],f[i^(1<<(k-1))][j][l]+inside[k][l]);
}
}
}
}
}
}
}
}
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
ans=std::max(ans,f[(1<<n)-1][i][j]+between[i][j]);
}
}
printf("%d\n",len-ans);
return 0;
}