[Trie树建图 2-SAT] Codeforces Gym 101190 NEERC 16 B. Binary Code

把所有串都扔进字典树 如果有两个是祖先和子孙的关系 就不能共存 那么我们直接用字典树辅助建一下图 跑2-SAT就好了
ps. 同时一个点上只能有一个 还要用前后缀建一下图
说起来真轻松

#include
#include
#include
#include
#include
using namespace std;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
inline int read(char *s){
  char c=nc(); int len=0;
  for (;!(c=='0' || c=='1' || c=='?');c=nc());
  for (;c=='0' || c=='1' || c=='?';s[++len]=c,c=nc()); s[++len]=0; return len-1;
}

const int N=4000005; //
const int M=10000005; //

struct edge{
  int u,v,next;
}G[M];
int head[N],inum;
inline void add(int u,int v){
  int p=++inum; G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}
#define V G[p].v
int pre[N],low[N],clk;
int scc[N],cnt; int Stack[N],pnt;
#define V G[p].v
inline void dfs(int u){
  pre[u]=low[u]=++clk; Stack[++pnt]=u;
  for (int p=head[u];p;p=G[p].next)
    if (!pre[V])
      dfs(V),low[u]=min(low[u],low[V]);
    else if (!scc[V])
      low[u]=min(low[u],pre[V]);
  if (low[u]==pre[u]){
    ++cnt;
    while (Stack[pnt]!=u) scc[Stack[pnt--]]=cnt; scc[Stack[pnt--]]=cnt; 
  }
}

const int ND=1000005;

int ncnt=1,rt=1;
int ch[ND][2],par[ND];
int pos[ND<<1];

inline void ins(char *s,int len,int idx){
  int p=rt;
  for (int i=1;i<=len;i++){
    int t=s[i]=='1';
    if (ch[p][t]==0) ch[p][t]=++ncnt,par[ncnt]=p;
    p=ch[p][t];
  }
  pos[idx]=p-1;
}

vector<int> lst[ND];
int n,Tot;
int blank[ND],Ans[ND];
char S[ND<<1]; int len;
char *str[N];
int tmp[ND<<1];

inline bool cmp(int a,int b){
  return pos[a]int main(){
  char *s=S;
  freopen("binary.in","r",stdin);
  freopen("binary.out","w",stdout);
  read(n);
  for (int i=0;i1;
    *s='\n';
    int t=0;
    for (int j=1;j<=len;j++) if (str[i][j]=='?') t=j;
    blank[i]=t;
    if (!t){
      ins(str[i],len,i<<1);
      pos[i<<1|1]=pos[i<<1];
      add(i<<1,i<<1|1);
    }
    else{
      str[i][t]='0';
      ins(str[i],len,i<<1);
      str[i][t]='1';
      ins(str[i],len,i<<1|1);
    }
  }
  Tot=n<<1;
  for (int i=1;i<=ncnt;i++)
    for (int j=0;j<2;j++)
      if (ch[i][j]){
    add(Tot+((i-1)<<1),Tot+((ch[i][j]-1)<<1));
    add(Tot+((ch[i][j]-1)<<1|1),Tot+((i-1)<<1|1));
      }
  for (int i=0;i<(n<<1);i++){
    lst[pos[i]].push_back(i);
    if (ch[pos[i]+1][0])
      add(i,Tot+((ch[pos[i]+1][0]-1)<<1));
    if (ch[pos[i]+1][1])
      add(i,Tot+((ch[pos[i]+1][1]-1)<<1));
    add(i,Tot+((par[pos[i]+1]-1)<<1|1));
    add(Tot+(pos[i]<<1),i^1);
    add(Tot+(pos[i]<<1|1),i^1);
  }
  Tot=Tot+(ncnt<<1);
  for (int i=0;iif ((int)lst[i].size()>1){
      int tmp=Tot;
      for (int j=0;j<(int)lst[i].size();j++){
    add(tmp+j,lst[i][j]^1);
    if (j-1>=0)
      add(tmp+j,tmp+j-1);
      }
      tmp+=(int)lst[i].size();
      for (int j=0;j<(int)lst[i].size();j++){
    add(tmp+j,lst[i][j]^1);
    if (j+1<(int)lst[i].size())
      add(tmp+j,tmp+j+1);
      }
      for (int j=0;j<(int)lst[i].size();j++){
    if (j-1>=0)
      add(lst[i][j],Tot+j-1);
    if (j+1<(int)lst[i].size())
      add(lst[i][j],tmp+j+1);
      }
      Tot+=2*(int)lst[i].size();
    }
  for (int i=0;iif (!pre[i])
      dfs(i);
  for (int i=0;iif (scc[i<<1]==scc[i<<1|1])
      printf("NO\n"),exit(0);
    else
      Ans[i]=scc[i<<1]1|1]?0:1;
  for (int i=0;iif (blank[i])
      str[i][blank[i]]='0'+Ans[i];
  printf("YES\n");
  printf("%s",S+1);
  return 0;
}

你可能感兴趣的:(字典树,2-SAT)