题意:你要给字母表的前 m m m个字母排列,定义每对字母的距离: d i s t ( s i , s j ) = a b s ( i − j ) dist(s_{i}, s_{j})=abs(i-j) dist(si,sj)=abs(i−j),给定一个长度为 n n n的字符串 s s s,求 ∑ i = 2 n d i s t ( s i − 1 , s i ) \sum_{i = 2}^{n}dist(s_{i-1},s_{i}) ∑i=2ndist(si−1,si)
解法:设 c n t [ s ] cnt[s] cnt[s]为 s s s二进制下 1 1 1的数量,设 w [ i ] [ j ] w[i][j] w[i][j]为字母 i i i和字母 j j j在 s s s中相邻的次数,我们逐位来填字母,设 d p [ S ] dp[S] dp[S]为前 c n t [ S ] cnt[S] cnt[S]位填的字母集合为 S S S,每个已填的字母对其他所有字母在前 c n t [ S ] cnt[S] cnt[S]位的贡献的总和的最小值为 d p [ S ] dp[S] dp[S],假设我们接下来在 c n t [ S ] + 1 cnt[S]+1 cnt[S]+1位又填了一个字母使得状态变成了 S 2 S2 S2,对于 i ∈ S 2 i \in S2 i∈S2, j ∉ S 2 j \notin S2 j∈/S2,显然又增加一次距离的贡献,那么 d p [ S 2 ] = m i n ( d p [ S 2 ] , d p [ S ] + w [ i ] [ j ] ) dp[S2]=min(dp[S2],dp[S]+w[i][j]) dp[S2]=min(dp[S2],dp[S]+w[i][j]), 2 m m 2 2^{m}m^{2} 2mm2复杂度即可解决这题
//预处理可以降低一个m
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int a[21], w[21][21], dp[1 << 20];
char s[maxn];
int main() {
int n, m;
scanf("%d%d%s", &n, &m, s + 1);
for (int i = 2; i <= n; i++) {
int u = s[i] - 'a';
int v = s[i - 1] - 'a';
w[u][v]++;
w[v][u]++;
}
int N = 1 << m;
for (int i = 1; i < N; i++) {
dp[i] = 1e9;
for (int j = 0; (1 << j) <= i; j++)
if (i >> j & 1)
dp[i] = min(dp[i], dp[i ^ (1 << j)]);
for (int j = 0; (1 << j) <= i; j++)
if (i >> j & 1)
for (int k = 0; k < m; k++)
if (!(i >> k & 1))
dp[i] += w[j][k];
}
printf("%d\n", dp[N - 1]);
}