题目大意:给你一个字符串,要你按每组k个按照顺序进行分组,每组里的字母顺序任意,然后再按照组的顺序拼起来,如果相邻的几个相同的字母算一个块,拼起来后,最少的块是多少?
所以要最小每组相同字母肯定在一起,所以每组枚举结尾字母即可,dp[i][j] 表示 第i组 字母j 结尾 的最小值
如果第i组结尾和第i-1组结尾字母相同 如果 i组的 size==1 则 相等 否则 dp[i-1] + size;
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <set>
using namespace std;
#define clr(a, x) memset(a, x, sizeof(a))
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define REP(i,a,b) for(int i=a;i<=b;i++)
const int maxn = 1010 ;
char str[maxn];
set<char>s[maxn];
int dp[maxn][30];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int k;
scanf("%d",&k);
scanf("%s",str);
int len=strlen(str);
int n=len/k;
for(int i=0;i<=n;i++) s[i].clear();
for(int i=0;i<len;i++)
{
s[i/k].insert(str[i]);
}
set<char>::iterator it,mt;
for(it=s[0].begin();it!=s[0].end();it++)
{
dp[0][(*it)-'a']=(int)s[0].size();
}
for(int i=1;i<n;i++)
{
for(mt = s[i].begin();mt!= s[i].end();mt++)
{
dp[i][(*mt)-'a']=maxn;
for(it= s[i-1].begin();it!=s[i-1].end();it++)
{
if((*mt)==(*it)) dp[i][(*mt)-'a']=min(dp[i][(*mt)-'a'],dp[i-1][(*it)-'a']+(s[i].size()==1?0:(int)s[i].size()));
else
{
if( s[i].find((*it)) !=s[i].end())
{
dp[i][(*mt)-'a']=min(dp[i][(*mt)-'a'],dp[i-1][(*it)-'a']+(int)s[i].size()-1);
}
else
{
dp[i][(*mt)-'a']=min(dp[i][(*mt)-'a'],dp[i-1][(*it)-'a']+(int)s[i].size());
}
}
}
}
}
int ans=maxn;
for(it= s[n-1].begin();it!=s[n-1].end();it++)
{
ans=min(ans,dp[n-1][(*it)-'a']);
}
printf("%d\n",ans);
}
return 0;
}