CodeForces EduRound 74

E: Keyboard Purchase

题意

给你一个有小写字母组成的字符串,让你给每个字母编号,使得$\sum\limits{i=1}^{n}|S_i-S{i-1}|$的值最小

思路

因为字母种类很小,所以我们可以用类似状压来记录中间值,具体的是$dp[(1<<m)]$来记录当前状态出现的字母种类与还未出现的字母种类的距离。

我们现在先想象一个键盘,$dp[i]$的二进制表示就是键盘前几个的键,那么$dp[i]$的转移就是由$dp[i^(1<<j)]$新加了一位j转移得来:

1
2
3
4
5
for (int i = 1; i < (1<<m); i ++) {
dp[i] = 0x3f3f3f3f;
for (int j = 0; (1<<j) <= i; j ++)
if((i>>j)&1) dp[i] = min(dp[i], dp[i^(1<<j)]);
}

得到的就是当前状态下的最小花费,

那么这样的话,原来的$dp[i^(1<<j)]$的状态不确定的这一位已经确定,那么其他还尚未却动的键与当前已经确定的键之间的距离要$+1$,

1
2
3
4
5
6
7
8
9
for (int i = 1; i < (1<<m); i ++) {
dp[i] = 0x3f3f3f3f;
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] += adj[j][k];
}

AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include<bits/stdc++.h>
using namespace std;

#define ll long long
const int maxn = 1e5 + 7;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
typedef pair<int, int> pis;

int dp[(1<<21)];
int adj[30][30];

int main() {
int n, m;
scanf("%d %d", &n, &m);
string st;
cin >> st;
for (int i = 1; i < st.size(); i ++) {
adj[st[i]-'a'][st[i-1]-'a'] ++;
adj[st[i-1]-'a'][st[i]-'a'] ++;
}
for (int i = 1; i < (1<<m); i ++) {
dp[i] = 0x3f3f3f3f;
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] += adj[j][k];
}
printf("%d\n", dp[(1<<m)-1]);
return 0;
}
---------Thanks for your attention---------