1238E

状压dp

看起来不是很好状压 反过来考虑计算贡献 $dp[S]$表示当前已经放置了集合$S$的字母 $S$内部距离之和以及$S$内部摆放方法距离对于外部还未选的字母的贡献和 这样外面怎么放不会影响当前状态的最优 因为当添加一个字母在末尾 它和$S$的未计算的贡献只有一个间隔 之前的间隔已经计算了 其实就是$bzoj4033$的思想 但是我没看出来

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1 << 22;
int n, m;
int dp[maxn], d[30][30], sum[maxn];
char s[maxn];
int main() {
    scanf("%d%d%s", &n, &m, s + 1);
    for(int i = 2; i <= n; ++i) {
        ++d[s[i] - 'a'][s[i - 1] - 'a'];
        ++d[s[i - 1] - 'a'][s[i] - 'a'];
    }
    for(int i = 0; i < m; ++i) {
        d[i][i] = 0;
    }
    memset(dp, 0x3f3f, sizeof(dp));
    dp[0] = 0;
    for(int S = 1; S < 1 << m; ++S) {
        int p = S & (-S);
        for(int i = 0; i < m; ++i) {
            if((1 << i) == p) {
                p = i;
                break;
            }
        }
        for(int i = 0; i < m; ++i) {
            if(S >> i & 1) {
                sum[S] -= d[p][i];
            } else {
                sum[S] += d[p][i];
            }
        }
        sum[S] += sum[S ^ (1 << p)];
        for(int i = 0; i < m; ++i) {
            if(S >> i & 1) {
                dp[S] = min(dp[S], dp[S ^ (1 << i)] + sum[S]);
            }
        }
    }
    printf("%d\n", dp[(1 << m) - 1]);
    return 0;
}
View Code

 

posted @ 2020-01-27 22:54  19992147  阅读(156)  评论(0编辑  收藏  举报