bzoj3508: 开灯

题目链接

题解

\(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 ;
}

猜你喜欢

转载自www.cnblogs.com/zzy2005/p/11737221.html
今日推荐