给你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;
}

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

  1. 【二分图】【并查集】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem L. Canonical duel

    给你一个网格(n<=2000,m<=2000),有一些炸弹,你可以选择一个空的位置,再放一个炸弹并将其引爆,一个炸弹爆炸后,其所在行和列的所有炸弹都会爆炸,连锁反应. 问你所能引爆的最多炸 ...

  2. Codeforces Round #543 (Div. 2) F dp + 二分 + 字符串哈希

    https://codeforces.com/contest/1121/problem/F 题意 给你一个有n(<=5000)个字符的串,有两种压缩字符的方法: 1. 压缩单一字符,代价为a 2 ...

  3. 【哈希表】Ural Championship April 30, 2017 Problem H. Hamburgers

    题意:有n群人,每个人有喜欢的汉堡配方:有m家店,给出每家店的每个汉堡的配方,如果存在某个汉堡,其配料表包含某个人喜欢的配方,则这个人喜欢这个汉堡所在的店家.问你对每群人,输出被喜欢的人数最多的店面是 ...

  4. 【二分】【三分】【计算几何】XIII Open Championship of Y.Kupala Grodno SU Grodno, Saturday, April 29, 2017 Problem L. Lines and Polygon

    题意:给你一个凸多边形,和多次询问,每次询问给你一条直线,问你这条直线与凸包上的顶点的最近距离是多少. 记当前询问的直线的斜率为K, 先找到与这条直线距离最远的两个点: 就把凸包所有的边当做有向直线进 ...

  5. HDU 1045 - Fire Net - [DFS][二分图最大匹配][匈牙利算法模板][最大流求二分图最大匹配]

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=1045 Time Limit: 2000/1000 MS (Java/Others) Mem ...

  6. 二分图的最大匹配——最大流EK算法

    序: 既然是个图,并且求边数的最大值.那么这就可以转化为网络流的求最大流问题. 只需要将源点与其中一子集的所有节点相连,汇点与另一子集的所有节点相连,将所有弧的流量限制置为1,那么最大流 == 最大匹 ...

  7. 【CodeForces】961 F. k-substrings 字符串哈希+二分

    [题目]F. k-substrings [题意]给定长度为n的串S,对于S的每个k-子串$s_ks_{k+1}...s_{n-k+1},k\in[1,\left \lceil \frac{n}{2} ...

  8. 【BZOJ4443】[Scoi2015]小凸玩矩阵 二分+二分图最大匹配

    [BZOJ4443][Scoi2015]小凸玩矩阵 Description 小凸和小方是好朋友,小方给小凸一个N*M(N<=M)的矩阵A,要求小秃从其中选出N个数,其中任意两个数字不能在同一行或 ...

  9. 【bzoj3291】Alice与能源计划 模拟费用流+二分图最大匹配

    题目描述 在梦境中,Alice来到了火星.不知为何,转眼间Alice被任命为火星能源部长,并立刻面临着一个严峻的考验. 为了方便,我们可以将火星抽象成平面,并建立平面直角坐标系.火星上一共有N个居民点 ...

随机推荐

  1. shell中的IFS和$*变量

    本文转载自http://blog.chinaunix.net/uid-22566367-id-381955.html 自我记录内容.在工程中遇到了相关内容的shell脚本.在此处记录 STRING1= ...

  2. (十六)strtok、strtok_s、strtok_r 字符串分割函数

    1.strtok函数 函数原型:char * strtok (char *str, const char * delimiters); 参数:str,待分割的字符串(c-string):delimit ...

  3. Scrapy爬虫:抓取大量斗图网站最新表情图片

      一:目标 第一次使用Scrapy框架遇到很多坑,坚持去搜索,修改代码就可以解决问题.这次爬取的是一个斗图网站的最新表情图片www.doutula.com/photo/list,练习使用Scrapy ...

  4. java8新特性视频、spring4.0视频讲解,javaee基础知识讲解等网址汇总

    1.http://ke.atguigu.com/     海量视频首页 2.http://ke.atguigu.com/course/56    java8新特性学习地址

  5. 让我们来一起学习OC吧

    在本分类中的接下来的将翻译http://rypress.com/tutorials/objective-c/index 通过每一章节的翻译,使得自己的OC基础扎实并分享给大家.

  6. 内核添加USB模块

    Device Drivers->SCSI device support->SCSI disk support Device Drivers->USB support->Supp ...

  7. FineReport——巧妙实现类tab布局

    在FR中,表达form支持局部刷新和tab布局,在报表中,不能做到这样,只能舍弃一些功能来做到类似的tab布局. 首先,在参数面板放一个文本控件temp,用作一个临时值,需要设置一个默认值,而切换是通 ...

  8. ueditor在QQ浏览器或者IE浏览器中无法加载

    因为IE浏览器有兼容问题,打开网址,浏览器不一定以最新的文档模式加载.按F12查看 在你网址的head标签中加入:<meta http-equiv="x-ua-compatible&q ...

  9. 【python】r+,w+ 全局变量

    来源:http://www.educity.cn/wenda/352188.html r+:可读可写,若文件不存在,报错w+: 可读可写,若文件不存在,创建文本模式:遇换行符时根据操作系统不同自动转换 ...

  10. HDU 3045 picnic cows(斜率DP)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3045 题目大意:有n个数,可以把n个数分成若干组,每组不得小于m个数,每组的价值=除了该组最小值以外每 ...