#2-SAT,Tarjan,前后缀优化建图,Trie#洛谷 6965 LOJ 6036 [NEERC 2016] Binary Code
分析
其实就是针对前缀的关系建边转化为 2-SAT 判定和输出方案。
问题是怎么建边,考虑建 Trie,为了避免自己连向自己,将 Trie 复制一份
如果 y 是 x 的前缀,那么 x 连向第一棵 Trie,状态的父节点连向 neg(y)
如果 y 是 x 的前缀,那么 y 连向第二棵 Trie,状态的父节点连向 neg(x)
第一棵 Trie 儿子连父亲,第二棵 Trie 父亲连儿子,就实现了不同串的建边。
相同串就单独进行前后缀优化建图即可。
代码
#include <iostream>
#include <string>
#include <vector>
#include <stack>
using namespace std;
const int N=3000011; struct node{int y,next;}e[N<<3]; vector<int>ed[N]; stack<int>st;
int trie[N][2],rk[N],fat[N],tot,cnt,color,v[N],dfn[N],low[N],as[N],col[N],n,m,et;
void Insert(string s,int id){
int p=1,len=s.length();
for (int i=0;i<len;++i){
if (!trie[p][s[i]-48]) fat[trie[p][s[i]-48]=++tot]=p;
p=trie[p][s[i]-48];
}
ed[p].push_back(id),rk[id]=p;
}
void add(int x,int y){e[++et]=(node){y,as[x]},as[x]=et;}
void print(int p){
if (p==1) return;
print(fat[p]);
if (trie[fat[p]][1]==p) cout<<1;
else cout<<0;
}
void tarjan(int x){
dfn[x]=low[x]=++cnt,v[x]=1,st.push(x);
for (int i=as[x];i;i=e[i].next)
if (!dfn[e[i].y]){
tarjan(e[i].y);
low[x]=min(low[x],low[e[i].y]);
}else if (v[e[i].y]) low[x]=min(low[x],dfn[e[i].y]);
if (dfn[x]==low[x]){
int y; ++color;
do{
y=st.top(),v[y]=0;
col[y]=color;
st.pop();
}while (y!=x);
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n,tot=1;
if (n>33333){
cout<<"NO";
return 0;
}
for (int i=1;i<=n;++i){
string s; cin>>s;
int len=s.length(),pos=-1;
for (int j=0;j<len;++j)
if (s[j]=='?'){
s[j]='0';
Insert(s,i<<1);
s[j]='1';
Insert(s,i<<1|1);
pos=j;
break;
}
if (pos==-1){
Insert(s,i<<1);
rk[i<<1|1]=rk[i<<1];
add(i<<1|1,i<<1);
}
}
m=(n+tot)*2+1;
for (int i=2;i<=tot;++i){
add((i+n)<<1|1,(fat[i]+n)<<1|1);
if (ed[i].size()>1){
int siz=ed[i].size();
add(m+1,ed[i][0]^1);
for (int j=1;j<siz;++j){
add(m+j+1,m+j);
add(ed[i][j],m+j);
add(m+j+1,ed[i][j]^1);
}
m+=siz;
add(m+siz,ed[i][siz-1]^1);
for (int j=siz-2;~j;--j){
add(m+j+1,m+j+2);
add(ed[i][j],m+j+2);
add(m+j+1,ed[i][j]^1);
}
m+=siz;
}
add((fat[i]+n)<<1,(i+n)<<1);
}
for (int i=1;i<=n;++i){
add((rk[i<<1]+n)<<1|1,i<<1|1),add(i<<1,(fat[rk[i<<1]]+n)<<1|1);
add((rk[i<<1|1]+n)<<1|1,i<<1),add(i<<1|1,(fat[rk[i<<1|1]]+n)<<1|1);
add(i<<1,(rk[i<<1]+n)<<1),add((fat[rk[i<<1]]+n)<<1,i<<1|1);
add(i<<1|1,(rk[i<<1|1]+n)<<1),add((fat[rk[i<<1|1]]+n)<<1,i<<1);
}
for (int i=2;i<=m;++i) if (!dfn[i]) tarjan(i);
for (int i=1;i<=n;++i)
if (col[i<<1]==col[i<<1|1]){
cout<<"NO";
return 0;
}
cout<<"YES"<<'\n';
for (int i=1;i<=n;++i,cout<<'\n')
if (col[i<<1]<col[i<<1|1]) print(rk[i<<1]);
else print(rk[i<<1|1]);
return 0;
}

浙公网安备 33010602011771号