给你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. tensorflow常用函数解析

    一.tf.transpose函数的用法 tf.transpose(input, [dimension_1, dimenaion_2,..,dimension_n]):这个函数主要适用于交换输入张量的不 ...

  2. 基于ansj_seg和nlp-lang的简单nlp工具类

    1.首先在pom中引入ansj_seg和nlp-lang的依赖包, ansj_seg包的作用: 这是一个基于n-Gram+CRF+HMM的中文分词的java实现: 分词速度达到每秒钟大约200万字左右 ...

  3. WAMP Apache 2.5 配置虚拟主机

    1.在 Apache 的安装目录下 conf/httpd.conf 文件中搜索 hosts,去掉 Include 前面的 “#” 号后,即可启用虚拟主机. # Virtual hosts #Inclu ...

  4. 爬虫===登陆CSDN的方法

    本文主要介绍csdn的登陆,可应用在爬虫上~ # -*- coding:utf-8 -*- import json import requestsfrom xlutils.copy import co ...

  5. telnet如何保存输出内容到本地

    telnet如何保存输出内容到本地 http://bbs.csdn.net/topics/391023327 一种将程序的标准输出重定向到telnet终端的方法 http://blog.chinaun ...

  6. 非 GUI 模式运行 JMeter 压力测试

    非 GUI 模式,即命令行模式,运行 JMeter 测试脚本能够大大缩减所需要的系统资源. 使用命令:jmeter -n -t <testplan filename> -l <lis ...

  7. leetcode 343. Integer Break(dp或数学推导)

    Given a positive integer n, break it into the sum of at least two positive integers and maximize the ...

  8. 几个例子理解对称加密与非对称加密、公钥与私钥、签名与验签、数字证书、HTTPS加密方式

    # 原创,转载请留言联系 为什么会出现这么多加密啊,公钥私钥啊,签名啊这些东西呢?说到底还是保证双方通信的安全性与完整性.例如小明发一封表白邮件给小红,他总不希望给别人看见吧.而各种各样的技术就是为了 ...

  9. pom报错解决方法大全

    1.Failure to transfer org.apache.maven.plugins:maven-surefire-plugin:pom 解决方法: Windows: CMD --> c ...

  10. mysql设置服务器编码

    今天写java程序的时候出现了插入mysql数据中文乱码问题,确定数据库和表的编码都已指定utf-8.百度后得知mysql安装后需设置服务器编码,以下是解决方法(ubuntu; mysql 5.6.2 ...