动态规划。
dp【i】【j】【k】表示前i组中,第i组以j开头以k结束时的最小组数。
这样取a【j】=min{dp【i-1】【k】【j】},该组内块数为val
则dp【i】【k】【q】=if k==j min{dp【i】【k】【q】,a【j】+val-1}
else min{dp【i】【k】【q】,a【j】+val}
动态规划算法可能有当前状态之前的多个状态转移而来,而这个题只由前一个状态转移而来,因此可以使用滚动数组优化空间。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#define ll long long
#define INF 2139062143
#define inf -2139062144
#define MOD 20071027
#define MAXN 1005
using namespace std;
int dp[30][30];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int d;
char str[MAXN];
scanf("%d%s",&d,str);
int L=strlen(str),n=L/d;
memset(dp,0x7f,sizeof(dp));
for(int i=0; i<n; ++i)
{
bool vis[30]= {0};
int st=i*d,ed=(i+1)*d;
for(int j=st; j<ed; ++j)
vis[str[j]-'a']=true;
int val=0;
for(int j=0; j<26; ++j)
if(vis[j]) val++;
if(i==0)
{
if(val==1)
dp[str[0]-'a'][str[0]-'a']=1;
else
{
for(int j=0; j<26; ++j)
for(int k=0; k<26; ++k)
if(vis[j]&&vis[k]&&j!=k) dp[j][k]=val;
}
}
else
{
int a[MAXN];
memset(a,0x7f,sizeof(a));
for(int j=0; j<26; ++j)
for(int k=0; k<26; ++k)
a[k]=min(a[k],dp[j][k]);
memset(dp,0x7f,sizeof(dp));
if(val==1)
{
int t=str[st]-'a';
for(int j=0; j<26; ++j)
if(a[j]!=INF)
{
if(t==j) dp[t][t]=min(dp[t][t],a[j]);
else dp[t][t]=min(dp[t][t],a[j]+1);
}
}
else
{
for(int j=0; j<26; ++j)
for(int k=0; k<26; ++k)
for(int q=0; q<26; ++q)
if(vis[k]&&vis[q]&&k!=q&&a[j]!=INF)
{
if(k==j) dp[k][q]=min(dp[k][q],a[j]+val-1);
else dp[k][q]=min(dp[k][q],a[j]+val);
}
}
}
}
int ans=INF;
for(int i=0; i<26; ++i)
for(int j=0; j<26; ++j)
ans=min(dp[i][j],ans);
printf("%d\n",ans);
}
return 0;
}