[SDOI2012]棋盘覆盖 网络流+FFT+状压DP

版权声明:xgc原创文章,未经允许不得转载。 https://blog.csdn.net/xgc_woker/article/details/82431396

Description
在一个N*M个方格组成的棋盘内,有K个方格被称为特殊方格。我们要使用一组俄罗斯方块来覆盖这个棋盘,保证特殊方格不能被覆盖,非特殊方格只能被一个俄罗斯方块覆盖,求最多能容纳的俄罗斯方块的数量。
已知有以下三组俄罗斯方块,一个棋盘可能用其中的某一组。
这里写图片描述


Sample Input1
8 8 0 A
Sample Input2
7 6 6 C
3 1
3 6
5 3
5 4
5 7
6 7


Sample Output1
32
Sample Output2
12


这道题看一眼数据范围:有趣。
第一组,是个例题吧。。。
黑白染色,跑网络流。
第二组,只有一个k???
那不是 n n 1 3 ,n,m巨大,FFT一波。
第三组三进制状压DP(肯定可以跑过去,这辈子都不可能卡掉的)


#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const double phi = acos(-1.0);
const int dx[4] = {0, 1, 0, -1};
const int dy[4] = {1, 0, -1, 0};
int _min(int x, int y) {return x < y ? x : y;}
int _max(int x, int y) {return x > y ? x : y;}

struct Complex {
    double r, i;
    Complex() {r = i = 0;}
    Complex(double _r, double _i) {r = _r, i = _i;}
    friend Complex operator + (Complex a, Complex b) {return Complex(a.r + b.r, a.i + b.i);}
    friend Complex operator - (Complex a, Complex b) {return Complex(a.r - b.r, a.i - b.i);}
    friend Complex operator * (Complex a, Complex b) {return Complex(a.r * b.r - a.i * b.i, a.i * b.r + a.r * b.i);}
} a[210000], b[210000];
struct node {
    int len, a[210000];
    node() {len = 0; memset(a, 0, sizeof(a));}
} A, B;
struct edge {
    int x, y, c, next;
} e[210000]; int len, last[11000];
int st, ed, h[11000];
bool mp[110][110];
queue<int> q;
char ss[11], s1[210000], s2[210000];
int R[210000], c[210000];
int now, f[2][210000];
int n, m, C[15], D[15];
int plen[2], p[2][210000];
bool v[210000];

void back(int x) {
    int num = 0;
    while(x) C[++num] = x % 3, x /= 3;
}

int gett(int c[]) {
    int hh = 1, sum = 0;
    for(int i = 1; i <= m; i++) sum += hh * c[i], hh *= 3;
    return sum;
}

void ins(int x, int y, int c) {
    e[++len].x = x; e[len].y = y; e[len].c = c;
    e[len].next = last[x]; last[x] = len;
    e[++len].x = y; e[len].y = x; e[len].c = 0;
    e[len].next = last[y]; last[y] = len;
}

bool bfs() {
    memset(h, 0, sizeof(h)); h[st] = 1;
    q.push(st);
    while(!q.empty()) {
        int x = q.front(); q.pop();
        for(int k = last[x]; k; k = e[k].next) {
            int y = e[k].y;
            if(e[k].c && !h[y]) h[y] = h[x] + 1, q.push(y);
        }
    } if(!h[ed]) return 0; else return 1;
}

int dfs(int x, int flow) {
    if(x == ed) return flow;
    int tt = 0, minf;
    for(int k = last[x]; k; k = e[k].next) {
        int y = e[k].y;
        if(h[y] == h[x] + 1 && e[k].c && tt < flow) {
            minf = dfs(y, _min(e[k].c, flow - tt));
            e[k].c -= minf; e[k ^ 1].c += minf;
            tt += minf;
        }
    } if(!tt) h[x] = 0;
    return tt;
}

int chu(int h) {
    int las = 0;
    for(int i = h; i >= 0; i--) {
        c[i] += las;
        las = (c[i] % 3) * 10;
        c[i] /= 3;
    } while(!c[h]) h--;
    return h;
}

void fft(Complex *y, int len, int o) {
    for(int i = 0; i < len; i++) if(i < R[i]) swap(y[i], y[R[i]]);
    for(int i = 1; i < len; i *= 2) {
        Complex wn(cos(phi / i), sin(o * phi / i));
        for(int j = 0; j < len; j += i * 2) {
            Complex w(1, 0);
            for(int k = 0; k < i; k++, w = w * wn) {
                Complex u = y[j + k];
                Complex v = w * y[j + k + i];
                y[j + k] = u + v;
                y[j + k + i] = u - v;
            }
        }
    } if(o == -1) for(int i = 0; i < len; i++) y[i].r /= len;
}

void Dfs(int k, int hh, int s) {
    if(k > m) {
        int p1 = gett(C), p2 = gett(D);
        if(!v[p2]) v[p2] = 1, p[now][++plen[now]] = p2;
        f[now][p2] = _max(f[now][p2], f[now ^ 1][p1] + s);
        return ;
    }
    if(C[k] == 2) {D[k] = 1; Dfs(k + 1, hh, s); D[k] = 0; return ;}
    if(hh <= n - 2 && !mp[hh][k] && !mp[hh + 1][k] && !mp[hh + 2][k] && !C[k] && !D[k]) D[k] = 2, Dfs(k + 1, hh, s + 1), D[k] = 0;
    if(k <= m - 2 && !C[k] && !C[k + 1] && !C[k + 2] && !mp[hh][k] && !mp[hh][k + 1] && !mp[hh][k + 2]) Dfs(k + 3, hh, s + 1), D[k] = 0;
    if(k <= m - 1 && hh < n) {
        if(!C[k] && !C[k + 1] && !mp[hh][k] && !mp[hh][k + 1]) {
            if(!D[k] && !mp[hh + 1][k]) D[k] = 1, Dfs(k + 2, hh, s + 1), D[k] = 0;
            if(!mp[hh + 1][k + 1]) D[k + 1] = 1, Dfs(k + 2, hh, s + 1), D[k + 1] = 0;
        }
        if(!D[k] && C[k] != 2 && C[k + 1] != 2 && !mp[hh + 1][k] && !mp[hh + 1][k + 1]) {
            if(!C[k] && !mp[hh][k]) D[k] = D[k + 1] = 1, Dfs(k + 2, hh, s + 1), D[k] = D[k + 1] = 0;
            else if(!C[k + 1] && !mp[hh][k + 1]) D[k] = D[k + 1] = 1, Dfs(k + 2, hh, s + 1), D[k] = D[k + 1] = 0;
        }
    }
    Dfs(k + 1, hh, s);
}

int main() {
    scanf("%s%s", s1 + 1, s2 + 1);
    int k; scanf("%d", &k);
    scanf("%s", ss + 1);
    if(ss[1] == 'A') {
        n = 0, m = 0;
        for(int i = 1; i <= strlen(s1 + 1); i++) n = n * 10 + s1[i] - '0';
        for(int i = 1; i <= strlen(s2 + 1); i++) m = m * 10 + s2[i] - '0';
        for(int i = 1; i <= k; i++) {
            int x, y; scanf("%d%d", &x, &y);
            mp[x][y] = 1;
        }
        len = 1; st = 0, ed = n * m + 1;
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++) if(((i + j) & 1) && !mp[i][j]){
                for(int k = 0; k < 4; k++) {
                    int nx = i + dx[k], ny = j + dy[k];
                    if(nx > 0 && nx <= n && ny > 0 && ny <= m && !mp[nx][ny]) ins((i - 1) * m + j, (nx - 1) * m + ny, 1);
                }
            }
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++) if(((i + j) & 1) && !mp[i][j]){
                ins(st, (i - 1) * m + j, 1);
            }
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++) if(!((i + j) & 1) && !mp[i][j]){
                ins((i - 1) * m + j, ed, 1);
            }
        int ans = 0;
        while(bfs()) ans += dfs(st, 999999999);
        printf("%d\n", ans);
    } else if(ss[1] == 'B') {
        n, m; 
        A.len = strlen(s1 + 1);
        for(int i = 1; i <= A.len; i++) A.a[i] = s1[A.len - i + 1] - '0';
        n = m = A.len - 1;
        for(int i = 0; i <= n; i++) a[i].r = A.a[i + 1];
        for(int i = 0; i <= m; i++) b[i].r = A.a[i + 1];
        m += n + 2; int L = 0;
        for(n = 1; n <= m; n *= 2) L++;
        for(int i = 0; i < n; i++) R[i] = (R[i >> 1] >> 1) | (i & 1) << (L - 1);
        fft(a, n, 1), fft(b, n, 1);
        for(int i = 0; i <= n; i++) a[i] = a[i] * b[i];
        fft(a, n, -1);
        for(int i = 0; i < n; i++) c[i] = int(a[i].r + 0.5);
        for(int i = 0; i < n; i++) {
            c[i + 1] += c[i] / 10;
            c[i] %= 10;
        } while(n && c[n] <= 0) n--;
        c[0]--; int u = 0;
        while(c[u] < 0) c[u] += 10, c[u + 1]--;
        n = chu(n);
        for(int i = n; i >= 0; i--) printf("%d", c[i]);
        printf("\n");
    } else {
        n = 0, m = 0;
        for(int i = 1; i <= strlen(s1 + 1); i++) n = n * 10 + s1[i] - '0';
        for(int i = 1; i <= strlen(s2 + 1); i++) m = m * 10 + s2[i] - '0';
        for(int i = 1; i <= k; i++) {
            int x, y; scanf("%d%d", &x, &y);
            mp[x][y] = 1;
        } now = 0; p[0][plen[0] = 1] = 0;
        f[0][0] = 0;
        for(int i = 1; i <= n; i++) {
            memset(v, 0, sizeof(v));
            now ^= 1; memset(f[now], -1, sizeof(f[now]));
            plen[now] = 0;
            for(int j = 1; j <= plen[now ^ 1]; j++) {
                memset(C, 0, sizeof(C)); memset(D, 0, sizeof(D));
                back(p[now ^ 1][j]);
                Dfs(1, i, 0);
            }
        } int maxx = 0;
        for(int i = 1; i <= plen[now]; i++) 
        maxx = _max(maxx, f[now][p[now][i]]);
        printf("%d\n", maxx);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xgc_woker/article/details/82431396