jzoj1242.PermRLE

Description

文本压缩的算法有很多种,这里给出一种叫做PermRLE的压缩算法、
定义一个整数k, PermRLE算法依赖于一种压缩顺序。所谓的压缩顺序就是一种1~k的排列。例如当k=4的时候,其中一种排列方式是{1,2,4,3},对于字符串“abdb”,按照这种排列方式进行排列之后就变成了“abbd”。
对于一段长度为Len的文本,其中k能整除Len,那么PermRLE算法就是把整个文本分成Len div k段,然后每一段按照一种1~k的排列方式进行重新排列,重新排列完之后,就把这Len div k段进行合并。对于合并之后得到一个新字符串,PermRLE算法就是把字符串中连续相同的字符合并成一个字符,例如aabccaabb合并后就变成了abcab。
给出一段长度为len(1<=len<=50000)的文本以及一个整数k(1<=k<=16)其中k能整除Len,你的任务就是找出一种1~k的排列,使得PermRLE算法压缩之后的文本的长度最小。当然,为了降低难度,你只需输出文本压缩之后最小的长度,而不需要输出这种排列。

Input

输入第一行有一个整数k(1<=k<=16),意义如上所述。
接下来一行有一个字符串,保证字符串的长度能被k整除,且字符串里仅含有小写字母。

Output

输出一行,仅包含文本压缩之后的最小长度。

Sample Input

输入1:
4
abcabcabcabc

输入2:
3
abcabcabcabc

Sample out

输出1:
7

输出2:
12

Data Constraint

对于50%的数据,1<=k<=5,1<=len<=1000
对于100%的数据,1<=k<=16,1<=len<=50000

Solution

根据题意,我们是要选择一个关于K的排列,使得连续重复的字符最多。K很小,又是关于排列,于是我们可以用状压DP解决。
FS,i F S , i 表示当前K的排列中使用过的数是那些, i i 表示最后一个放入S中的是那个数,最多能够删除多少字符。
那么此时,我们就能够表示出关于K的排列,我们只需要知道转移的代价是什么就好了。这个东西我们可以预处理出来
Blocki,j B l o c k i , j 表示在 N/K N / K 个块中 i i 位置和j的字符相同的块有多少,那么转移方程就可以列出来:

FS,i=max(FS,i,FS,j+Blockj,i) F S , i = m a x ( F S , i , F S ′ , j + B l o c k j , i )

现在还要处理的就是块与块之间交接的重复字符,但我们就要知道第一个放入的K的排列中的数是什么。我们首先预处理一个 Nexi,j N e x i , j 表示每个块与它下一个块第 i i 个字符和第j个字符有多少个相同的,那么我们就可以做K次状压DP,每一次选取一个开头,从它开始转移。那么
Ans=min(Ans,F(1<<k)1,i+Nexj,i)[ij] A n s = m i n ( A n s , F ( 1 << k ) − 1 , i + N e x j , i ) [ i 是 枚 举 最 后 一 个 放 入 的 数 , j 是 第 一 个 放 入 的 数 ]

最终的输出答案就是 NAns N − A n s ,时间复杂度为 O(NK+K32K) O ( N K + K 3 2 K )

Code

# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std;
const int N = 5e4 + 5;
const int K = (1 << 16) + 5;
char s[N];
int f[K][20],nx[20][20],block[20][20];
int ans,k,len;
int main()
{
    scanf("%d%s",&k,s + 1); len = strlen(s + 1);
    for (int i = 0 ; i < len / k ; ++i)
        for (int j = 1 ; j <= k ; ++j)
            for (int l = 1 ; l <= k ; ++l)
            {
                block[j][l] += s[i * k + j] == s[i * k + l];
                if (k * (i + 1) + l <= len) nx[j][l] += s[i * k + j] == s[k * (i + 1) + l];
            }
    int lim = (1 << k) - 1; 
    for (int s = 1 ; s <= k ; ++s)
    {
        memset(f,-0x3f,sizeof(f)); f[1 << (s - 1)][s] = 0;
        for (int i = 0 ; i <= lim ; ++i)
        {
            for (int j = 1 ; j <= k ; ++j)
                if (i & (1 << (j - 1)))
                    for (int l = 1 ; l <= k ; ++l)
                        if (i & (1 << (l - 1)) && j != l)
                            f[i][j] = max(f[i][j],f[i ^ (1 << (j - 1))][l] + block[j][l]);
        }
        for (int i = 1 ; i <= k ; ++i)
            for (int j = 1 ; j <= k ; ++j)
                if (i != j) ans = max(ans,f[lim][j] + nx[j][s]);
    }
    printf("%d\n",len - ans);
    return 0;
}
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。、可私 6信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。、可 6私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。、可私 6信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值