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

bzoj3508: 开灯

时间:2019-10-25 13:32:55      阅读:74      评论:0      收藏:0      [点我收藏+]

标签:状压   front   first   for   eof   链接   ble   set   zoj   

题目链接

题解

\(b[i]=a[i]\ xor\ a[i+1]\)

我们可以发现,修改只会改变\(b[l-1]\)\(b[r]\)

然后发现\(b[i]=1\)的点最多\(2*k\)

状压\(dp\)

Code

void bfs(int s) {
    memset(vis, 0, sizeof(vis));
    vis[s] = 1; q.push(make_pair(s, 0));
    while (!q.empty()) {
        int u = q.front().first, d = q.front().second; q.pop();
        if (b[u]) g[num[s]][num[u]] = d;
        for (int i = 1; i <= l; i++) {
            if (u + a[i] <= n && !vis[u + a[i]])
                vis[u + a[i]] = 1, q.push(make_pair(u + a[i], d + 1));
            if (u - a[i] >= 0 && !vis[u - a[i]])
                vis[u - a[i]] = 1, q.push(make_pair(u - a[i], d + 1));
        }
    }  
}
void solve() {
    n = gi<int>(), k = gi<int>(), l = gi<int>();
    memset(b, 0, sizeof(b)); tot = 0;
    for (int i = 1; i <= k; i++) b[gi<int>()] = 1;
    for (int i = 0; i <= n; i++)
        if (b[i] ^= b[i + 1])
            num[i] = tot++;
    for (int i = 1; i <= l; i++) a[i] = gi<int>();
    int lim = 1 << tot;
    memset(g, 0x3f, sizeof(g));
    memset(f, 0x3f, sizeof(f));
    for (int i = 0; i <= n; i++)
        if (b[i]) bfs(i);
    f[0] = 0;
    for (int i = 1, p; i < lim; i++) {
        p = 0; while (!(i & 1 << p)) p++;
        for (int j = p + 1; j < tot; j++)
            if (i & 1 << j)
                f[i] = min(f[i], f[i ^ 1 << p ^ 1 << j] + g[j][p]);
    }
    printf("%d\n", f[lim - 1] > inf ? -1 : f[lim - 1]);
    return ;
}

bzoj3508: 开灯

标签:状压   front   first   for   eof   链接   ble   set   zoj   

原文地址:https://www.cnblogs.com/zzy2005/p/11737221.html

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