Luogu3825 NOI2017 游戏 2-SAT

传送门


第一眼看上去似乎是一个3-SAT问题

然而\(d \leq 8\)给我们的信息就是:暴力枚举

枚举\(x\)型地图变成\(a\)型地图还是\(b\)型地图(实际上不要枚举\(c\),因为\(ab\)两种地图已经包含了选择\(ABC\)三辆车的情况),对于每一种情况跑2-SAT即可。复杂度\(O(2^d(n+m))\)

还有为什么UOJ的Hack那么强啊QAQ

随机化要么WA EX5要么WA EX8,不随机化TLE EX9

#include<bits/stdc++.h>
//This code is written by Itst
using namespace std;

inline int read(){
    int a = 0;
    char c = getchar();
    bool f = 0;
    while(!isdigit(c)){
        if(c == '-')
            f = 1;
        c = getchar();
    }
    while(isdigit(c)){
        a = (a << 3) + (a << 1) + (c ^ '0');
        c = getchar();
    }
    return f ? -a : a;
}

const int MAXN = 2e5 + 3 , T = 190;
struct Edge{
    int end , upEd;
}Ed[MAXN << 1];
int head[MAXN] , dfn[MAXN] , low[MAXN] , in[MAXN] , st[MAXN] , ban[MAXN];
int cntEd , top , ts , cntX , N , M , scc , x[9] , ys[MAXN][4];
char s[MAXN];
bool ins[MAXN];

inline void addEd(int a , int b){
    Ed[++cntEd].end = b;
    Ed[cntEd].upEd = head[a];
    head[a] = cntEd;
}

inline char getc(){
    char c = getchar();
    while(!islower(c))
        return c;
    return c;
}

void tarjan(int x){
    dfn[x] = low[x] = ++ts;
    ins[x] = 1;
    st[++top] = x;
    for(int i = head[x] ; i ; i = Ed[i].upEd){
        if(!dfn[Ed[i].end])
            tarjan(Ed[i].end);
        else
            if(!ins[Ed[i].end])
                continue;
        low[x] = min(low[x] , low[Ed[i].end]);
    }
    if(dfn[x] == low[x]){
        ++scc;
        do{
            ins[st[top]] = 0;
            in[st[top]] = scc; 
        }while(st[top--] != x);
    }
}

#define calc(ys , p) ((ys) + ((p) == 2 - (ban[ys] == 2)) * N)
bool solve(){
    memset(dfn , 0 , sizeof(int) * (N * 2 + 1));
    memset(head , 0 , sizeof(int) * (N * 2 + 1));
    cntEd = ts = scc = 0;
    for(int i = 1 ; i <= M ; ++i){
        if(ban[ys[i][0]] == ys[i][1])
            continue;
        if(ban[ys[i][2]] == ys[i][3]){
            addEd(calc(ys[i][0] , ys[i][1]) , calc(ys[i][0] , 3 - ban[ys[i][0]] - ys[i][1]));
            continue;
        }
        int p = calc(ys[i][0] , ys[i][1]) , q = calc(ys[i][2] , ys[i][3]);
        addEd(p , q);
        addEd(q + (q > N ? -N : N) , p + (p > N ? -N : N));
    }
    for(int i = 1 ; i <= N * 2 ; ++i)
        if(!dfn[i])
            tarjan(i);
    for(int i = 1 ; i <= N ; ++i)
        if(in[i] == in[i + N])
            return 0;
    return 1;
}

deque < int > q;

int main(){
    #ifndef ONLINE_JUDGE
    //freopen("in" , "r" , stdin);
    //freopen("out" , "w" , stdout);
    #endif
    srand((unsigned)time(0));
    N = read();
    read();
    scanf("%s" , s + 1);
    for(int i = 1 ; i <= N ; ++i)
        if(s[i] == 'x')
            x[cntX++] = i;
        else
            ban[i] = s[i] - 'a';
    M = read();
    for(int i = 1 ; i <= M ; ++i){
        ys[i][0] = read();
        ys[i][1] = getc() - 'A';
        ys[i][2] = read();
        ys[i][3] = getc() - 'A';
    }
    for(int i = 0 ; i < 1 << cntX ; ++i)
        q.push_back(i);
    srand((unsigned)time(0));
    random_shuffle(q.begin() , q.end());
    for(int i = T ; i >= 0 && !q.empty() ; --i){
        int t = q.front();
        q.pop_front();
        random_shuffle(q.begin() , q.end());
        for(int j = 0 ; j < cntX ; ++j)
            ban[x[j]] = (bool)(t & (1 << j));
        if(solve()){
            for(int j = 1 ; j <= N ; ++j)
                switch(ban[j]){
                    case 0:
                        putchar('B' + (in[j] > in[j + N]));
                        break;
                    case 1:
                        putchar('A' + (in[j] > in[j + N]) * 2);
                        break;
                    case 2:
                        putchar('A' + (in[j] > in[j + N]));
                }
            return 0;
        }
    }
    printf("-1");
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Itst/p/10352637.html