luoguP3943 星空 最短路 一般圖的最大匹配 狀壓Dp

luoguP3943 星空

題目傳送門

分析

區間操作很難搞,一個巧妙的轉化是,把原區間差分,這樣的話異或操作就變成了將某兩個位置取反。
原問題轉化爲某個01序列上有若干個1,每次可以把距離爲bi+1b_i+1的兩個1取反,求把這個序列清空的最少操作次數。
考慮如果只有兩個11,實際上就是跑一個最短路。
如果求出了每個11兩兩之間的距離,這樣的話就轉化成了一個一般圖上的最大匹配問題。
上帶花樹啊
開始最多88個點,考慮狀壓,每次枚舉最左的未匹配的節點去和別的節點匹配轉移即可。

代碼

#include<cstdio>
#include<cstring>
const int N = 4e4 + 10, M = 110, X = 1048576;
int ri() {
    char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
    for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
int d[M][N], c[M], a[M], q[N], f[X], bin[21], Lg[X], n, m, k, C; bool b[N];
void Up(int &a, int b) {b < a || !~a ? a = b : 0;}
void Bfs(int *d, int s) {
    int L = 1, R = 1; q[L] = s; d[s] = 1;
    for(int u = q[L]; L <= R; u = q[++L])
        for(int i = 1;i <= m; ++i) {
            if(u + c[i] <= n && !d[u + c[i]]) d[q[++R] = u + c[i]] = d[u] + 1;
            if(u - c[i] >= 0 && !d[u - c[i]]) d[q[++R] = u - c[i]] = d[u] + 1;
        }
}
int main() {
    n = ri(); k = ri(); m = ri();
    for(int i = 1, x;i <= k; ++i) x = ri(), b[x] ^= 1, b[x - 1] ^= 1;
    for(int i = 1;i <= m; ++i) c[i] = ri();
    for(int i = 0;i <= n; ++i) if(b[i]) a[C++] = i;
    for(int i = 0;i < C; ++i) Bfs(d[i], a[i]);
    std::memset(f, -1, sizeof(f)); f[0] = 0; 
    bin[0] = 1; for(int i = 1;i <= C; ++i) bin[i] = bin[i - 1] << 1, Lg[bin[i]] = Lg[bin[i - 1]] + 1;
    for(int i = 0;i < bin[C] - 1; ++i) if(~f[i]) {
        int j = Lg[(i + 1)&-(i + 1)];
        for(int k = j + 1;k < C; ++k) if(~i & bin[k])
            if(d[j][a[k]]) Up(f[i | bin[j] | bin[k]], f[i] + d[j][a[k]] - 1);
    }
    printf("%d\n", f[bin[C] - 1]);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章