dp[m][i][j]代表第m组以字母(i +'a') 开头和以字母 ( j + 'a' )结尾的最小块数。kuai[m]中存储了第 m 组最少可以分为多少块,显然最少为所有相同字母放在一起时的块数,即这一组中不同字母的个数。
如果前一组的结尾与后一组的开头相同,则dp[m][i][j] = min( dp[m-1][st][ed] + kuai[m] - 1 );
若不同,则dp[m][i][j] = min(dp[m - 1][st][ed] + kuai[m] );
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <algorithm> 5 6 using namespace std; 7 8 const int MAXN = 1010; 9 const int INF = 1 << 30; 10 11 char str[MAXN]; 12 int dp[MAXN][30][30]; 13 int kuai[MAXN]; //记录每组之中最小的块数 14 bool vis[MAXN][30]; //记录每组出现了哪些字母 15 int K, n; 16 17 void GetKuai() //预处理得到每组内最小的块数 18 { 19 memset( vis, false, sizeof(vis) ); 20 for ( int i = 0; i < n; ++i ) 21 { 22 int st = K * i; 23 int ed = K * (i + 1); 24 for ( int j = st; j < ed; ++j ) 25 vis[i][ str[j] - 'a' ] = true; 26 27 kuai[i] = 0; 28 for ( int j = 0; j < 26; ++j ) 29 if ( vis[i][j] ) ++kuai[i]; 30 } 31 return; 32 } 33 34 void init() //初始化 35 { 36 for ( int i = 0; i < 26; ++i ) 37 for ( int j = 0; j < 26; ++j ) 38 if ( vis[0][i] && vis[0][j] ) 39 dp[0][i][j] = kuai[0]; 40 else dp[0][i][j] = INF; 41 return; 42 } 43 44 void solved() 45 { 46 init(); 47 48 for ( int m = 1; m < n; ++m ) 49 for ( int i = 0; i < 26; ++i ) 50 { 51 if ( vis[m][i] ) 52 { 53 for ( int j = 0; j < 26; ++j ) 54 { 55 dp[m][i][j] = INF; 56 if ( ( j == i && kuai[m] == 1 ) || ( j != i && vis[m][j] ) ) // 这里WA了两次,首位字母不能相同,除非这一组内的块数为1 57 { 58 for ( int st = 0; st < 26; ++st ) 59 if ( vis[m - 1][st] ) 60 { 61 for ( int ed = 0; ed < 26; ++ed ) 62 { 63 if ( ( st == ed && kuai[m - 1] == 1 ) || ( ed != st && vis[m - 1][ed] ) ) 64 { 65 if ( ed == i ) 66 dp[m][i][j] = min( dp[m][i][j], dp[m - 1][st][ed] + kuai[m] - 1 ); 67 else dp[m][i][j] = min( dp[m][i][j], dp[m - 1][st][ed] + kuai[m] ); 68 } 69 } 70 } 71 } 72 } 73 } 74 } 75 76 int ans = INF; 77 for ( int i = 0; i < 26; ++i ) 78 for ( int j = 0; j < 26; ++j ) 79 if ( vis[n - 1][i] && vis[n - 1][j] ) 80 ans = min( ans, dp[n - 1][i][j] ); 81 82 printf( "%d\n", ans ); 83 return; 84 } 85 86 int main() 87 { 88 int T; 89 scanf( "%d", &T ); 90 while ( T-- ) 91 { 92 scanf( "%d%s", &K, str ); 93 n = strlen(str) / K; //得到块数 94 GetKuai(); 95 solved(); 96 } 97 return 0; 98 }