【二分】【字符串哈希】【二分图最大匹配】【最大流】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem I. Minimum Prefix

给你n个字符串,问你最小的长度的前缀,使得每个字符串任意循环滑动之后,这些前缀都两两不同。

二分答案mid之后,将每个字符串长度为mid的循环子串都哈希出来,相当于对每个字符串,找一个与其他字符串所选定的子串不同的子串,是个二分图最大匹配的模型,可以匈牙利或者Dinic跑最大流看是否满流。

一个小优化是对于某个字符串,如果其所有不同的子串数量超过n,那么一定满足,可以直接删去。

卡常数,不能用set,map啥的,采取了用数组记录哈希值,排序后二分的手段进行去重和离散化。

#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
#define INF 2147483647
#define MAXN 200301
#define MAXM 800501
int v[MAXM],cap[MAXM],en,first[MAXN],next[MAXM];
int d[MAXN],cur[MAXN];
queue<int>q;
int n,S,T;
void Init_Dinic(){memset(first,-1,sizeof(first)); en=0;}
void AddEdge(const int &U,const int &V,const int &W)
{
    v[en]=V; cap[en]=W;
    next[en]=first[U]; first[U]=en++;
    v[en]=U; cap[en]=0;
    next[en]=first[V]; first[V]=en++;
}
bool bfs()
{
    memset(d,-1,sizeof(d)); q.push(S); d[S]=0;
    while(!q.empty())
      {
          int U=q.front(); q.pop();
          for(int i=first[U];i!=-1;i=next[i])
            if(d[v[i]]==-1 && cap[i])
              {
                d[v[i]]=d[U]+1;
                q.push(v[i]);
              }
      }
    return d[T]!=-1;
}
int dfs(int U,int a)
{
    if(U==T || !a) return a;
    int Flow=0,f;
    for(int &i=cur[U];i!=-1;i=next[i])
      if(d[U]+1==d[v[i]] && (f=dfs(v[i],min(a,cap[i]))))
        {
          cap[i]-=f; cap[i^1]+=f;
          Flow+=f; a-=f; if(!a) break;
        }
    if(!Flow) d[U]=-1;
    return Flow;
}
int max_flow()
{
    int Flow=0,tmp=0;
    while(bfs())
      {
          memcpy(cur,first,sizeof(first));
          while(tmp=dfs(S,INF)) Flow+=tmp;
      }
    return Flow;
}
typedef unsigned long long ull;
const ull base=107;
ull bs[200005],hss[200005],hss2[200005];
char* a[205];
char b[200005];
int tmphss[200005];
bool neednot[205];
int len[205],pps[205],ppsend[205];
bool check(int x){
	int pp=0;
	Init_Dinic();
	memset(neednot,0,sizeof(neednot));
	int N=n;
	for(int i=1;i<=n;++i){
		int last=pp;
		pps[i]=last+1;
		int FirstPre=min(len[i],x);
		ull hs=0;
		for(int j=0;j<FirstPre;++j){
			hs=hs*base+(ull)a[i][j];
		}
		hss[++pp]=hs;
		for(int j=FirstPre;j<len[i];++j){
			hs-=(bs[x-1]*(ull)a[i][j-x]);
			hs=hs*base+(ull)a[i][j];
			hss[++pp]=hs;
		}
		for(int j=0;j<FirstPre-1;++j){
			hs-=(bs[FirstPre-1]*(ull)a[i][len[i]-FirstPre+j]);
			hs=hs*base+(ull)a[i][j];
			hss[++pp]=hs;
		}
		sort(hss+last+1,hss+pp+1);
		int Size=0;
		for(int j=last+2;j<=pp;++j){
			if(hss[j]!=hss[j-1]){
				++Size;
			}
		}
		if(Size>n){
			--N;
			neednot[i]=1;
		}
		ppsend[i]=pp;
	}
	for(int i=1;i<=pp;++i){
		hss2[i]=hss[i];
	}
	sort(hss2+1,hss2+pp+1);
	S=n+pp+1;
	T=n+pp+2;
	for(int i=1;i<=n;++i){
		if(!neednot[i]){
			AddEdge(S,i,1);
			for(int j=pps[i];j<=ppsend[i];++j){
				if(j==pps[i] || hss[j]!=hss[j-1]){
					AddEdge(i,n+lower_bound(hss2+1,hss2+pp+1,hss[j])-hss2,1);
				}
			}
		}
	}
	for(int i=1;i<=pp;++i){
		if(i==1 || hss2[i]!=hss2[i-1]){
			AddEdge(i+n,T,1);
		}
	}
	return max_flow()>=N;
}
int main(){
//	freopen("i.in","r",stdin);
	bs[0]=1;
	for(int i=1;i<=200000;++i){
		bs[i]=bs[i-1]*base;
	}
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		scanf("%s",b);
		len[i]=strlen(b);
		a[i]=new char[len[i]+1];
		for(int j=0;j<len[i];++j){
			a[i][j]=b[j];
		}
	}
	int l=1,r=*max_element(len+1,len+n+1);
	while(l<r){
		int mid=(l+r>>1);
		if(check(mid)){
			r=mid;
		}
		else{
			l=mid+1;
		}
	}
	printf("%d
",l);
	return 0;
}
原文地址:https://www.cnblogs.com/autsky-jadek/p/7287033.html