【纪中集训2019.3.19】不同的缩写

题意:

描述

考虑用\(n\)个字符串\(t_{i}\)去代替\(n\)个字符串\(s_{i}\),满足\(t_{i}是s_{i}\)的子序列且\(t_{i}\)互不相同;

给出\(s_{i}\),最小化\(max \{ |t_{i}|\}\);

范围

\(n,|s_{i}| \ \le \ 300\);

题解:

  • 随机的情况下答案一般都是1,2;

  • 所以暴力找出所有长度为1和2的子序列进行匹配可以得到一部分分;

  • 二分答案\(mid\)

  • \(dfs\)找到所有长度小于等于\(mid\)的子序列连边,做二分图匹配;

  • 当一个点找到的不相同的子序列超过\(n\)个时一定有匹配,就不需要再继续\(dfs\)了;

  • 所以最多一共\(n^2\)个点,\(n^2\)条边;

  • 期望复杂度:\(O(log \ n \ n^2\sqrt{n^2}) = O(n^3 \ log \ n)\);

  • 常数较小;

    #include<bits/stdc++.h>
    using namespace std;
    const int N=310,M=1000010;
    int n,sz,l[N],nxt[N][N][26],mid,cur,cnt,T,vis[M],p[M],q[N];
    int ch[M][26],fa[M],fm[M];
    char s[N][N];
    vector<int>g[N];
    void print(int x){
      if(fa[x])print(fa[x]);
      putchar(fm[x]+'a');
    }
    bool match(int u){
      for(int i=0;i<g[u].size();++i){
          int v=g[u][i];
          if(vis[v]==T)continue;
          vis[v]=T;
          if(!p[v]||match(p[v])){
              p[v]=u;q[u]=v;
              return true;
          }
      }
      return false;
    }
    int CH(int x,int y){
      if(ch[x][y])return ch[x][y];
      ch[x][y]=++sz;
      memset(ch[sz],0,sizeof(ch[sz]));
      fm[sz]=y;fa[sz]=x;p[sz]=0;
      return sz;
    }
    void dfs(int t,int x,int y){
      if(cnt==n)return;
      if(y)g[t].push_back(cur),++cnt;
      if(y==mid)return;
      for(int i=0;i<26;++i)if(nxt[t][x][i]<=l[t]){
          cur=CH(cur,i);
          dfs(t,nxt[t][x][i],y+1);
          cur=fa[cur];
          if(cnt==n)break;
      }
    }
    bool check(){
      sz=0;
      memset(ch[0],0,sizeof(ch[0]));
      for(int i=1;i<=n;++i){
          g[i].clear();
          cur=cnt=0;
          dfs(i,0,0);
      }
      ++T;for(int i=1;i<=n;++i,++T)
      if(!match(i))return false;
      return true;
    }
    int main(){
      freopen("diff.in","r",stdin);
      freopen("diff.out","w",stdout);
      scanf("%d",&n);
      int mx=0;
      for(int i=1;i<=n;++i){
          scanf("%s",s[i]+1);
          l[i]=strlen(s[i]+1);
          for(int j=0;j<26;++j)nxt[i][l[i]][j]=l[i]+1;
          for(int j=l[i]-1;~j;--j){
              memcpy(nxt[i][j],nxt[i][j+1],sizeof(nxt[i][j]));
              nxt[i][j][s[i][j+1]-'a']=j+1;
          }
          mx=max(mx,l[i]);
      }
      int L=0,R=mx;
      while(L<R){
          mid=L+R>>1;
          if(check())R=mid;
          else L=mid+1;
      }
      mid=L;
      if(!check())puts("-1"),exit(0);else printf("%d\n",L);
      for(int i=1;i<=n;++i)print(q[i]),putchar('\n');
      return 0;
    }

猜你喜欢

转载自www.cnblogs.com/Paul-Guderian/p/10560554.html
今日推荐