简介:
把长度为S的字符串从左到右,每k个为一组,同组之间可以互相交换位置
使得重排后的字符串包含尽量少的块,其中每个块为连续的相同字符
分析:
我设计的状态是这样的
f[i][j] 表示第i组最后的字符为j,得到的最小块数
转移就需要枚举当前组的最后字符和上一组的最后字符
d=f[i-1][p]+(第i组包含的不同字符)
if (第i组中有p这个字符而且j!=p) d - -;
if (第i组中全是p这个字符) d - -;
f[i][j]=min{d}
一段区间内每个字符的出现次数,用前缀和维护
1A,震惊!!!
//这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
char s[1003];
int sum[1003][27],len,f[1003][27],k;
void doit()
{
int i,j,p,q;
int tt=0;
memset(f,0x33,sizeof(f));
for (i=0;i<26;i++)
if (sum[k][i]) tt++;
for (i=0;i<26;i++)
if (sum[k][i])
f[1][i]=tt;
for (i=2;i<=len/k;i++)
{
tt=0;
for (j=0;j<26;j++) if (sum[i*k][j]-sum[(i-1)*k][j]) tt++;
for (j=0;j<26;j++)
if (sum[i*k][j]-sum[(i-1)*k][j])
for (p=0;p<26;p++)
if (sum[(i-1)*k][p]-sum[(i-2)*k][p])
{
int d=f[i-1][p]+tt;
if (sum[i*k][p]-sum[(i-1)*k][p]&&(p!=j||sum[i*k][p]-sum[(i-1)*k][p]==k)) d--;
f[i][j]=min(f[i][j],d);
}
}
int ans=1e9;
for (i=0;i<26;i++) ans=min(ans,f[len/k][i]);
printf("%d\n",ans);
}
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
scanf("%d",&k);
scanf("%s",s+1);
len=strlen(s+1);
memset(sum,0,sizeof(sum));
for (int i=1;i<=len;i++)
{
for (int j=0;j<26;j++)
sum[i][j]=sum[i-1][j];
sum[i][s[i]-'a']++;
}
doit();
}
return 0;
}