首页 > 其他 > 详细

【LOJ#6036】编码

时间:2019-08-18 23:08:42      阅读:87      评论:0      收藏:0      [点我收藏+]

题面

https://loj.ac/problem/6036

题解

很抱歉的告诉大家,这道题我思考了很长时间,还是不会。

$yyb$代码的细节我也没有弄懂。我知道以后的学习中我会遇到很多这样的题,可能学习方式要进行转变了。

我只能把我看明白的部分讲给大家听。

首先是暴力,我们只要把$trie$树上具有“祖先-后代”关系的点对找出来,然后在他们之间连边,表示它们不能共存。

其次是优化,我们利用$trie$树的形态优化建边。

我们考虑对于每一个点,找到它祖先中所有的点连边(为什么不找到它所有的儿子连边?因为这样的话恐怕是对子树内所有的点连边,暴力的话复杂度就假了,我想的是点内后缀连边,点外$trie$树优化建边),

因为可能$trie$树上的一个位置可能躺着很多点,并且处于复杂度考虑,我们把“真正代表它自己的点”挂在$trie$树中它的位置之下。这样我们连边的时候只需要在$trie$树上找到所有它的祖先的位置,暴力连上去就好了(因为$\sum_{i=1}^{n}{s_i} \le 500000$),所以复杂度是对的。

这样做还有一个问题,我们连边不能连到自己的反,这样的话我们先建一个假点,如果发现要在它上面连边的时候直接建个新点上去,替换它的位置,再让新点向另一棵树中同一个位置的反,表示自己不能到这个点上,在把另一颗树的相同位置连向旧点,表示旧点的值和新点保持一致。这也是要预先排一遍序的原因。

#include<stack>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ri register int
#define N 3000300
using namespace std;
inline int read() {
  int ret=0,f=0; char ch=getchar();
  while (ch<0 || ch>9) f|=(ch==-),ch=getchar();
  while (ch>=0 && ch<=9) ret*=10,ret+=(ch-0),ch=getchar();
  return f?-ret:ret;
}
vector<int> to[N];

inline void add_edge(int u,int v) {
  to[u].push_back(v);
  u^=1; v^=1;
  to[v].push_back(u);
}
int dfn[N],low[N],clo,bel[N],cnt;
stack<int> sta; bool ins[N];
string s[N];

void tarjan(int x) {
  dfn[x]=low[x]=++clo;
  sta.push(x); ins[x]=1;
  for (ri i=0;i<to[x].size();++i) {
    int y=to[x][i];
    if (dfn[y]) {
      if (ins[y]) low[x]=min(low[x],dfn[y]);
    }
    else {
      tarjan(y);
      low[x]=min(low[x],low[y]);
    }
  }
  if (low[x]==dfn[x]) {
    ++cnt;
    while (1) {
      int t=sta.top(); sta.pop();
      bel[t]=cnt; ins[t]=0;
      if (t==x) break;
    }
  }
}

int ch[N][2],tot;
int n,len[N],id[N];
char ss[N];

void insert(int u,int p) {
  int x=n+1,lst=0;
  for (ri i=0;i<len[u];++i) {
    int c=s[u][i]-0;
    if (!ch[x][c]) ch[x][c]=++tot;
    lst=x; x=ch[x][c]; add_edge(p,x<<1);
  }
  int y=++tot;
  add_edge(p,y<<1|1); add_edge(y<<1,x<<1);
  ch[lst][s[u][len[u]-1]-0]=y;
}
bool cmp(int a,int b) {return len[a]<len[b];}

int main() {
  n=read();
  for (ri i=1;i<=n;++i) {
    scanf("%s",ss);
    len[i]=strlen(ss);
    id[i]=i;
    for (ri j=0;j<len[i];++j) s[i]+=ss[j];
  }
  sort(id+1,id+n+1,cmp);
  tot=n+1;
  for (ri i=1;i<=n;++i) {
    int u=id[i];
    for (ri j=0;j<len[u];++j) 
    if (s[u][j]==?) {
      s[u][j]=0; insert(u,u<<1);
      s[u][j]=1; insert(u,u<<1|1);
      break;
    }
    else if (j==len[u]-1) {
      insert(u,u<<1);
      add_edge(u<<1|1,u<<1);
    }
  }
  for (ri i=1;i<=(tot<<1|1);++i) 
  if (!dfn[i]) tarjan(i);
  for (ri i=1;i<=tot;++i)
  if (bel[i<<1]==bel[i<<1|1]) {
    puts("NO");
    return 0;
  }
  puts("YES");
  return 0;
}

 

【LOJ#6036】编码

原文:https://www.cnblogs.com/shxnb666/p/11373870.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!