LOJ6036 「雅礼集训 2017 Day4」 编码 2-SAT、Trie

传送门


每个串只有一个??还只能填0或者1,不难想到2-SAT求解。

一个很暴力的想法是枚举?0或者1,然后对所有可能的前缀连边。这样边数是(O(n^2))的,需要优化。

看到前缀不难想到Trie树。将所有串的所有可能形态填入Trie树中,然后使用前缀后缀优化2-SAT连边的方式优化连边。

具体来说对于每一个串开两个点表示?0还是1,对于Trie树上每一个串的结束节点也开两个点,表示这个点及其所有前缀中是否存在已经选过的串。

连边考虑一些互为前缀的串。设串为(s_1,s_2,s_3,...,s_k),第(i)个串在Trie树上的节点的(01)变量为(bool[i][0/1]),第(i)个节点对应串的(01)变量为(belong[i][0/1])(为了好描述,这里定义的(belong[i][0/1])表示第(i)个串填入01之后是否得到当前串,是为(1)

那么有边

(belong[i][1] ightarrow bool[i][1])

(bool[i][0] ightarrow bool[i -1][0])

(bool[i][1] ightarrow bool[i + 1][1])

(bool[i][0] ightarrow belong[i][0])

(bool[i][1] ightarrow belong[i + 1][0])

这些边可以在建Trie的过程中直接建。记得要建逆否命题的边。然后跑一遍缩点就行了

细节:①开始要将字符串按长度从小到大排序,才可以保证上面方法的正确性;②可能存在某些串相等,建Trie的时候要特别注意。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<queue>
#include<vector>
#define INF 0x3f3f3f3f
//This code is written by Itst
using namespace std;

const int MAXN = 3e6 + 3;
struct Edge{
	int end , upEd;
}Ed[MAXN << 3];
int head[MAXN] , N , cntN = 1 , cntEd;

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

namespace Trie{
	int ch[MAXN][2] , ind[MAXN] , cnt = 1;

	void insert(string s , int bl){
		int cur = 1 , up = 0;
		for(auto c : s){
			if(!ch[cur][c - '0'])
				ch[cur][c - '0'] = ++cnt;
			cur = ch[cur][c - '0'];
			if(ind[cur]) up = ind[cur];
		}
		cntN += 2;
		addEd(bl , cntN); addEd(cntN ^ 1 , bl ^ 1);
		if(up){
			addEd(up , cntN); addEd(cntN ^ 1 , up ^ 1);
			addEd(up , bl ^ 1); addEd(bl , up ^ 1);
		}
		ind[cur] = cntN;
	}
}
using Trie::insert;

int stk[MAXN] , dfn[MAXN] , low[MAXN] , in[MAXN];
int top , ts , cntSCC;
bool vis[MAXN] , ins[MAXN];

void pop(int x){
	++cntSCC;
	do{
		in[stk[top]] = cntSCC;
		ins[stk[top]] = 0;
	}while(stk[top--] != x);
}

void tarjan(int x , int p){
	vis[x] = ins[x] = 1;
	stk[++top] = x;
	dfn[x] = low[x] = ++ts;
	for(int i = head[x] ; i ; i = Ed[i].upEd){
		if(!vis[Ed[i].end]) tarjan(Ed[i].end , x);
		else if(!ins[Ed[i].end]) continue;
		low[x] = min(low[x] , low[Ed[i].end]);
	}
	if(dfn[x] == low[x]) pop(x);
}

vector < string > str;

bool cmp(string a , string b){return a.size() < b.size();}

int main(){
#ifndef ONLINE_JUDGE
	freopen("in","r",stdin);
	//freopen("out","w",stdout);
#endif
	cin >> N;
	for(int i = 1 ; i <= N ; ++i){
		string s;
		cin >> s;
		str.push_back(s);
	}
	sort(str.begin() , str.end() , cmp);
	for(auto t : str){
		cntN += 2;
		int nd = cntN , pos = t.find('?');
		if(pos != string::npos){
			t[pos] = '0';
			insert(t , nd - 1);
			t[pos] = '1';
			insert(t , nd);
		}
		else{
			insert(t , nd);
			addEd(nd - 1 , nd);
		}
	}
	for(int i = 2 ; i <= cntN ; ++i)
		if(!vis[i]) tarjan(i , 0);
	for(int i = 2 ; i <= cntN ; i += 2)
		if(in[i] == in[i + 1])
			return puts("NO") , 0;
	puts("YES");
	return 0;
}
原文地址:https://www.cnblogs.com/Itst/p/10467861.html