zoukankan      html  css  js  c++  java
  • 【纪中集训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^2sqrt{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
      ",L);
      	for(int i=1;i<=n;++i)print(q[i]),putchar('
      ');
      	return 0;
      }
      
  • 相关阅读:
    nginx能访问html静态文件但无法访问php文件
    LeetCode "498. Diagonal Traverse"
    LeetCode "Teemo Attacking"
    LeetCode "501. Find Mode in Binary Search Tree"
    LeetCode "483. Smallest Good Base" !!
    LeetCode "467. Unique Substrings in Wraparound String" !!
    LeetCode "437. Path Sum III"
    LeetCode "454. 4Sum II"
    LeetCode "445. Add Two Numbers II"
    LeetCode "486. Predict the Winner" !!
  • 原文地址:https://www.cnblogs.com/Paul-Guderian/p/10560554.html
Copyright © 2011-2022 走看看