题目描述

  懒得写了。。。直接贴题面

  

  $\sum n\leq5000,1\leq S_{i,j}\leq k\leq 1000 $

题解

  先建出广义sam。

  可以发现朋友的出现位置的定义符合后缀自动机的right集合的定义,如果一群人会相互产生感情,那么这一群人的特征值序列一定是sam中的同一个点(right集合相同)。

  然后发现题目求的就是用最少的“从根开始,在根之外的点不想交的路径”覆盖整个sam。

  这是一个经典问题,可以用网络流解决。

  把除了根之外每个点拆成两个点,两个点之间连上下界都是\(1\)的边。sam中的转移连下界为\(0\)上界为\(1\)边。所有点都往汇点连下界为\(0\)上界为\(1\)的边。

  上下界最小流就是答案。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<utility>
#include<iostream>
#include<tr1/unordered_map>
#include<queue>
using namespace std;
using namespace tr1;
typedef long long ll;
typedef pair<int,int> pii;
void open(const char *s)
{
#ifndef ONLINE_JUDGE
char str[100];
sprintf(str,"%s.in",s);
freopen(str,"r",stdin);
sprintf(str,"%s.out",s);
freopen(str,"w",stdout);
#endif
}
namespace flow
{
int u[1000010];
int v[1000010];
int h[100010];
int t[1000010];
int c[1000010];
int cnt;
void add2(int a,int b,int d)
{
cnt++;
u[cnt]=a;
v[cnt]=b;
c[cnt]=d;
t[cnt]=h[a];
h[a]=cnt;
}
void add(int x,int y,int v)
{
add2(x,y,v);
add2(y,x,0);
}
int S,T;
void add(int x,int y,int u,int v)
{
add(x,T,u);
add(S,y,u);
add(x,y,v-u);
}
int num;
int e[1000010];
int d[1000010];
int cur[100010];
queue<int> q;
int op(int x)
{
return ((x-1)^1)+1;
}
void init()
{
memset(d,-1,sizeof d);
d[T]=0;
q.push(T);
while(!q.empty())
{
int x=q.front();
q.pop();
e[d[x]]++;
for(int i=h[x];i;i=t[i])
if(c[op(i)]&&d[v[i]]==-1)
{
d[v[i]]=d[x]+1;
q.push(v[i]);
}
}
}
int dfs(int x,int flow)
{
if(x==T)
return flow;
int s=0,u;
for(int &i=cur[x];i;i=t[i])
if(c[i]&&d[v[i]]==d[x]-1)
{
u=dfs(v[i],min(c[i],flow));
flow-=u;
s+=u;
c[i]-=u;
c[op(i)]+=u;
if(!flow)
return s;
}
e[d[x]]--;
if(!e[d[x]])
d[S]=num;
d[x]++;
e[d[x]]++;
cur[x]=h[x];
return s;
}
int solve()
{
int ans=0;
init();
memcpy(cur,h,sizeof h);
while(d[S]>=0&&d[S]<=num-1)
ans+=dfs(S,0x3fffffff);
return ans;
}
}
namespace sam
{
unordered_map<int,int> next[10010];
int fail[10010];
int len[10010];
int n;
void init()
{
n=1;
}
int insert(int p,int c)
{
if(next[p][c])
{
int np=next[p][c];
if(len[np]==len[p]+1)
return np;
int nq=++n;
len[nq]=len[p]+1;
next[nq]=next[np];
fail[nq]=fail[np];
fail[np]=nq;
for(;p&&next[p][c]==np;p=fail[p])
next[p][c]=nq;
return nq;
}
int np=++n;
len[np]=len[p]+1;
for(;p&&!next[p][c];p=fail[p])
next[p][c]=np;
if(!p)
fail[np]=1;
else
{
int q=next[p][c];
if(len[q]==len[p]+1)
fail[np]=q;
else
{
int nq=++n;
len[nq]=len[p]+1;
next[nq]=next[q];
fail[nq]=fail[q];
fail[q]=fail[np]=nq;
for(;p&&next[p][c]==q;p=fail[p])
next[p][c]=nq;
}
}
return np;
}
}
int main()
{
open("friend");
int k,m,now,n,x;
scanf("%d%d",&k,&m);
sam::init();
while(m--)
{
now=1;
scanf("%d",&n);
while(n--)
{
scanf("%d",&x);
now=sam::insert(now,x);
}
}
flow::S=2*sam::n+1;
flow::T=2*sam::n+2;
flow::num=2*sam::n+2;
for(int i=2;i<=sam::n;i++)
{
flow::add(i*2-2,i*2-1,1,1);
flow::add(i*2-1,2*sam::n,0,1);
}
for(int i=1;i<=sam::n;i++)
for(auto v:sam::next[i])
flow::add(2*i-1,2*v.second-2,0,1);
flow::solve();
flow::add(2*sam::n,1,0,0x3fffffff);
int ans=flow::solve();
for(int i=1;i<=flow::cnt;i+=6)
{
if(flow::c[i])
{
printf("0\n");
return 0;
}
if(flow::c[i+2])
{
printf("0\n");
return 0;
}
}
printf("%d\n",ans);
return 0;
}

【XSY2767】朋友 广义后缀自动机 网络流的更多相关文章

  1. bzoj3926: [Zjoi2015]诸神眷顾的幻想乡 对[广义后缀自动机]的一些理解

    先说一下对后缀自动机的理解,主要是对构造过程的理解. 构造中,我们已经得到了前L个字符的后缀自动机,现在我们要得到L+1个字符的后缀自动机,什么需要改变呢? 首先,子串$[0,L+1)$对应的状态不存 ...

  2. BZOJ 3926 && ZJOI 2015 诸神眷顾的幻想乡 (广义后缀自动机)

    3926: [Zjoi2015]诸神眷顾的幻想乡 Time Limit: 10 Sec Memory Limit: 512 MB Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽 ...

  3. BZOJ 3277 串 (广义后缀自动机)

    3277: 串 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 309 Solved: 118 [Submit][Status][Discuss] De ...

  4. BZOJ 3473: 字符串 [广义后缀自动机]

    3473: 字符串 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 354  Solved: 160[Submit][Status][Discuss] ...

  5. BZOJ.2780.[SPOJ8093]Sevenk Love Oimaster(广义后缀自动机)

    题目链接 \(Description\) 给定n个模式串,多次询问一个串在多少个模式串中出现过.(字符集为26个小写字母) \(Solution\) 对每个询问串进行匹配最终会达到一个节点,我们需要得 ...

  6. BZOJ.3926.[ZJOI2015]诸神眷顾的幻想乡(广义后缀自动机)

    题目链接 要对多个串同时建立SAM,有两种方法: 1.将所有串拼起来,中间用分隔符隔开,插入字符正常插入即可. 2.在这些串的Trie上建SAM.实际上并不需要建Trie,还是只需要正常插入(因为本来 ...

  7. 【CF666E】Forensic Examination 广义后缀自动机+倍增+线段树合并

    [CF666E]Forensic Examination 题意:给你一个字符串s和一个字符串集合$\{t_i\}$.有q个询问,每次给出$l,r,p_l,p_r$,问$s[p_l,p_r]$在$t_l ...

  8. cf666E. Forensic Examination(广义后缀自动机 线段树合并)

    题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并 首先对所有的\(t_i\)建个广义后缀自动机,这样可以得到所有子串信息. 考虑把询问离线,然后把\(S\)拿到自动机上跑,同时维护一下 ...

  9. SP8093 JZPGYZ - Sevenk Love Oimaster(广义后缀自动机)

    题意 题目链接 Sol 广义后缀自动机板子题..和BZOJ串那个题很像 首先建出询问串的SAM,然后统计一下每个节点被多少个串包含 最后直接拿询问串上去跑就行了 #include<bits/st ...

随机推荐

  1. vue内置组件 transition 和 keep-alive 使用

    1.transition name - string,用于自动生成 CSS 过渡类名.例如:name: 'fade' 将自动拓展为.fade-enter,.fade-enter-active等.默认类 ...

  2. 微信小程序学习笔记以及VUE比较

    之前只是注册了一下微信小程序AppID,随便玩了玩HelloWorld!(项目起手式),但是最近看微信小程序/小游戏,崛起之势不可阻挡.小程序我来了!(果然,一入前端深似海啊啊啊啊啊~) 编辑器: S ...

  3. Vmware由于centos升级内核不可运行(C header files matching your running kernel were not found)的解决方案

    C header files matching your running kernel were not found. Refer to your distribution's documentati ...

  4. MySQL数据性能优化-修改方法与步骤

    原文:http://bbs.landingbj.com/t-0-240421-1.html 数据库优化应该是每个设计到数据库操作应用必须涉及到的操作. 经常调试修改数据库性能主要有三个方面 1.MyS ...

  5. rem移动端适配方案

    一. rem vs em 单位 定义 特点 rem font size of the root element 以根元素字体大小为基准 em font size of the element 以父元素 ...

  6. Oracle列转行函数LISTAGG()

    --Oracle列转行函数LISTAGG() with tb_temp as( select 'China' 国家,'Wuhan' 城市 from dual union all select 'Chi ...

  7. jQuery EasyUI 选项卡面板tabs使用实例精讲

    1. 对选项卡面板区域 div 设置 class=”easyui-tabs” 2. 对选项卡面板区域添加多个 div,每个 div 就是一个选项卡(每个面板一定设置 title) 3. 设置面板 fi ...

  8. Day 5-2 类的继承和派生,重用

    类的继承 派生 在子类中重用父类 组合 抽象类 定义: 继承指的是类与类之间的关系,是一种什么“是”什么的关系,继承的功能之一就是用来解决代码重用问题. 继承是一种创建新类的方式,在python中,新 ...

  9. CSS实现元素水平垂直居中

    我们知道,实现元素的水平居中比较简单,在设置了宽度后,设置左右margin为auto就可以. 但是如何设置元素垂直居中呢? 当然,对于单行的文字,可以通过设置line-height来解决, 可以对于一 ...

  10. linux audit审计(7-1)--读懂audit日志

     auid=0 auid记录Audit user ID,that is the loginuid.当我使用lbh用户登录系统时,再访问audit_test,此时记录的auid为1001,具体日志如下: ...