[CF1238E] Keyboard Purchase - 状压dp
Description
有m种小写字符,给定一个长为n的序列,定义编辑距离为序列中相邻两个字母位置差的绝对值之和,其中字母位置是一个1到m的排列 安排一种方案,求编辑距离最小 (n le 1e5,m le 20)
Solution
这里用到了拆贡献的思想
状压 DP,(f[s]) 中 (s) 当前已经确定选择的字母集合,值为当前已经加入的元素的贡献
转移考虑加入下一个字母时的影响:新加入的字母会导致已经加入的字母和未加入的字母之间的距离增加 (1)
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n, m;
string s;
const int N = 2e6 + 5;
const int M = 25;
int f[N];
int g[M][M];
signed main()
{
ios::sync_with_stdio(false);
cin >> n >> m >> s;
for (int i = 1; i < n; i++)
{
g[s[i - 1] - 'a'][s[i] - 'a']++;
g[s[i] - 'a'][s[i - 1] - 'a']++;
}
for (int s = 0; s < 1 << m; s++)
{
int c = 0;
for (int i = 0; i < m; i++)
if (s & (1 << i))
for (int j = 0; j < m; j++)
if (!(s & (1 << j)))
c += g[i][j];
if (s)
f[s] = 1e18;
for (int i = 0; i < m; i++)
if (s & (1 << i))
f[s] = min(f[s], f[s - (1 << i)] + c);
}
cout << f[(1 << m) - 1] << endl;
}