码迷,mamicode.com
首页 > 其他好文 > 详细

1238E

时间:2020-01-27 23:32:48      阅读:87      评论:0      收藏:0      [点我收藏+]

标签:col   img   amp   一个   click   nbsp   外部   print   alt   

状压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

 

1238E

标签:col   img   amp   一个   click   nbsp   外部   print   alt   

原文地址:https://www.cnblogs.com/19992147orz/p/12237148.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!