【二分】【字符串哈希】【二分图最大匹配】【最大流】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\n",l); return 0; }
——The Solution By AutSky_JadeK From UESTC
转载请注明出处:http://www.cnblogs.com/autsky-jadek/