老早以前的坑了
貌似好多地方都有这个题
因为每个串都只有一个问号,问号可取0可取1,这就是一个经典的2-SAT模型
但是直接做的话,边数是
n2
级别的,不过因为是01串,可以用可持久化字典树优化建图(可能也可以不可持久化,但是我觉得可持久化比较方便)
UPD:代码可能是假的,看http://blog.csdn.net/coldef/article/details/78303359
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <map>
#include <ctime>
#include <vector>
#include <stack>
#define N 2000010
using namespace std;
int n,cnt,g,flg;
int B[N],L[N],R[N],dfn[N],low[N],vis[N],wh[N],len[N],G[N];
char *A[N];
char M[N];
stack<int> S;
struct edge{
int t,nx;
}E[N];
inline void Insert(int x,int y){
E[++cnt].t=y; E[cnt].nx=G[x]; G[x]=cnt;
}
map<string,int> Mp;
struct trie{
int node[N][3],cnt,enin[N];
trie(){ cnt=1; }
void insert(char *a,int x,int len){
int k=1,i=0;
while(i<len){
if(node[k][a[i]-'0']) k=node[k][a[i]-'0'];
else k=node[k][a[i]-'0']=++cnt;
i++;
}
enin[k]=1;
}
bool check(char *a,int len){
int k=1,i=0;
while(i<len){
if(node[k][a[i]-'0']) k=node[k][a[i]-'0']; else return false;
if(enin[k]) return true;
i++;
}
return true;
}
}C;
struct itrie{
int node[N][3],cnt,enin[N],G[N],g;
itrie(){ cnt=1;}
void insert(char *a,int x,int len){
int k=1,i=0;
while(i<len){
if(node[k][a[i]-'0']) Insert(node[k][a[i]-'0']+g,cnt+1+g);
k=node[k][a[i]-'0']=++cnt;
i++;
}
Insert(k+g,x);
enin[k]=1;
}
void explore(char *a,int x,int len){
int k=1,i=0,w=0;
while(i<len){
k=node[k][a[i]-'0'];
if(enin[k]) w=k;
i++;
}
if(w) Insert(x,w+g);
}
}D,F;
void tarjan(int x){
low[x]=dfn[x]=++g; vis[x]=1;
S.push(x);
for(int i=G[x];i;i=E[i].nx){
if(!vis[E[i].t]){
tarjan(E[i].t);
low[x]=min(low[E[i].t],low[x]);
}
else if(vis[E[i].t]==1) low[x]=min(low[x],dfn[E[i].t]);
}
if(low[x]==dfn[x]){
++flg;
while(1){
int w=S.top(); S.pop();
vis[w]=2;
wh[w]=flg;
if(w==x||S.empty()) break;
}
}
}
int main(){
scanf("%d",&n);
for(int i=1,j;i<=n;i++){
scanf("%s",M); len[i]=strlen(M);
int tot=++Mp[M];
if(tot>3) return puts("NO"),0;
A[i]=new char[strlen(M)+5];
for(j=0;j<len[i];j++) A[i][j]=M[j];
for(j=0;j<len[i];j++) if(A[i][j]=='?') break;
if(j==len[i]) B[i]=-1;
else B[i]=j;
}
for(int i=1;i<=n;i++)
if(B[i]==-1) if(C.check(A[i],len[i])) return puts("NO"),0;
else C.insert(A[i],i,len[i]);
for(int i=1;i<=n;i++)
if(B[i]!=-1){
int k=0;
A[i][B[i]]='0';
if(C.check(A[i],len[i])) k+=1;
A[i][B[i]]='1';
if(C.check(A[i],len[i])) k+=2;
if(k==3) return puts("NO"),0;
if(!k) continue;
if(k==1)
A[i][B[i]]='1',C.insert(A[i],i,len[i]);
else
A[i][B[i]]='0',C.insert(A[i],i,len[i]);
B[i]=-1;
}
D.g=500000; F.g=1000000;
for(int i=1;i<=n;i++)
if(B[i]!=-1){
A[i][B[i]]='0';
D.explore(A[i],i<<1|1,len[i]);
A[i][B[i]]='1';
D.explore(A[i],i<<1,len[i]);
A[i][B[i]]='0';
D.insert(A[i],i<<1,len[i]);
A[i][B[i]]='1';
D.insert(A[i],i<<1|1,len[i]);
}
for(int i=n;i;i--)
if(B[i]!=-1){
A[i][B[i]]='0';
F.explore(A[i],i<<1|1,len[i]);
A[i][B[i]]='1';
F.explore(A[i],i<<1,len[i]);
A[i][B[i]]='0';
F.insert(A[i],i<<1,len[i]);
A[i][B[i]]='1';
F.insert(A[i],i<<1|1,len[i]);
}
for(int i=2;i<=(n<<1|1);i++)
if(!vis[i]) tarjan(i);
for(int i=1;i<=n;i++)
if(wh[i<<1]==wh[i<<1|1]) return puts("NO"),0;
puts("YES");
return 0;
}