[CF590E]Birthday
Posted StaroForgin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CF590E]Birthday相关的知识,希望对你有一定的参考价值。
Birthday
题解
首先,我们比较容易地吧这道题转化成图上的最大独立集问题。
对于点
i
i
i和点
j
j
j,如果它们之间存在包含关系,那么我们就在它们之间连一条边
(
i
,
j
)
(i,j)
(i,j),表示它们不能被同时选择。
显然,我们之后只需要选出最多的点使其不相连接即可。
我们先考虑如何构建出这个图。
这也就意味着我们要去判断字符串与字符串之间的包含关系,我们可以去考虑
A
C
AC
AC自动机。
显然,
A
C
AC
AC自动机的包含是可以通过跳
f
a
i
l
fail
fail链进行判断的。
每个节点的
f
a
i
l
fail
fail节点代表的串的是原节点代表的串的子串。
所以我们可以尝试对于每个节点都记录下来它经过跳
f
a
i
l
fail
fail链能够跳到的第一个终止节点是哪一个。
显然,这样我们将一个串上所有节点的第一个跳到的终止节点拿出来,就可以建出偏序关系的
D
A
G
DAG
DAG了。
再随便
F
l
o
y
e
d
Floyed
Floyed一下,就可以将原图还原出来了。
但得到原图后,我们要怎么求最大独立集呢?
最大独立集显然是等价于反图的最大团,当然,如果你直接求团是过不了的。
根据
D
i
l
w
o
r
t
h
Dilworth
Dilworth定理,我们可以把片集的转化到原图的最小链覆盖上面。
最小链覆盖是可以通过该上下界网络流求出的,注意由于我们是要求最小可行流,所以先跑出可行流后还要从
T
T
T往
S
S
S跑一次最大流,让流最小化。
显然,求出这个最小可行流后,我们就可以构造出我们的链覆盖,但怎么将链覆盖转化到独立集上呢?
我们可以尝试在每条链上选择一个点,使得所有点独立。
先将每条链选的点都放在链底,然后
c
h
e
c
k
check
check是否合法,如果不合法就把浅的哪个点往上跳,直到合法为止。
容易发现这样是可以构造出一组合法解的,应该是的。
时间复杂度 O ( ∑ l e n ∣ ∑ ∣ + n 3 + ∣ 网 络 流 ∣ ) O\\left(\\sum len|\\sum| + n^3+|网络流|\\right) O(∑len∣∑∣+n3+∣网络流∣)。
源码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
#define MAXN 10000005
#define MAXM 2005
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
const int mo=1e9+7;
const int INF=0x3f3f3f3f;
template<typename _T>
_T Fabs(_T x)return x<0?-x:x;
template<typename _T>
void read(_T &x)
_T f=1;x=0;char s=getchar();
while(s<'0'||s>'9')if(s=='-')f=-1;s=getchar();
while('0'<=s&&s<='9')x=(x<<3)+(x<<1)+(s^48);s=getchar();
x*=f;
template<typename _T>
void print(_T x)if(x>9)print(x/10);putchar(x%10+'0');
LL gcd(LL a,LL b)return !b?a:gcd(b,a%b);
int add(int x,int y,int p)return x+y<p?x+y:x+y-p;
void Add(int &x,int y,int p)x=add(x,y,p);
int qkpow(int a,int s,int p)int t=1;while(s)if(s&1)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1;return t;
int n,m,bg[805],ed[805],len[805],a[MAXN],pos[MAXN],fa[805],idx,id[805],cho[805];
int head[MAXM],tot,S,T,SS,TT,cnt,dis[MAXM],cur[MAXM],ip[805][805],bp[805];
bool mp[805][805];char str[MAXN];queue<int>q;
vector<int>vec[805];
struct edgeint to,nxt,flow,op;e[MAXM*300];
void addEdge(int u,int v,int f)e[++tot]=(edge)v,head[u],f;head[u]=tot;
void addedge(int u,int v,int f)
addEdge(u,v,f);e[tot].op=tot+1;
addEdge(v,u,0);e[tot].op=tot-1;
struct nodeint ch[2],fail,ed;;
class AC_Automaton
private:
node tr[MAXN];int tot;
public:
void init()++tot;
void insert(int l,int r,int od)
int now=1;
for(int i=l;i<=r;i++)
if(!tr[now].ch[a[i]])
tr[now].ch[a[i]]=++tot;
pos[i]=now=tr[now].ch[a[i]];
tr[now].ed=od;
void sakura()
while(!q.empty())q.pop();tr[1].fail=1;
for(int i=0;i<2;i++)
if(!tr[1].ch[i])tr[1].ch[i]=1;
else tr[tr[1].ch[i]].fail=1,q.push(tr[1].ch[i]);
while(!q.empty())
int u=q.front();q.pop();if(!tr[u].ed)tr[u].ed=tr[tr[u].fail].ed;
for(int i=0;i<2;i++)
if(!tr[u].ch[i])tr[u].ch[i]=tr[tr[u].fail].ch[i];
else tr[tr[u].ch[i]].fail=tr[tr[u].fail].ch[i],q.push(tr[u].ch[i]);
for(int i=1;i<=n;i++)
for(int j=bg[i];j<=ed[i];j++)
int x=tr[pos[j]].ed;
if(x&&x!=i)mp[i][x]=1;
int x=tr[tr[pos[ed[i]]].fail].ed;
if(x&&x!=i)mp[i][x]=1;
Tr;
bool bfs()
for(int i=1;i<=cnt;i++)cur[i]=head[i],dis[i]=0;
while(!q.empty())q.pop();q.push(S);dis[S]=1;
while(!q.empty())
int u=q.front();q.pop();
for(int i=head[u];i;i=e[i].nxt)
int v=e[i].to;if(dis[v]||!e[i].flow)continue;
q.push(v);dis[v]=dis[u]+1;
if(v==T)return 1;
return 0;
int dfs(int u,int maxf)
if(u==T)return maxf;int res=0;
for(int i=cur[u];i;cur[u]=i=e[i].nxt)
int v=e[i].to;if(!e[i].flow||dis[v]!=dis[u]+1)continue;
int tmp=dfs(v,min(maxf,e[i].flow));
maxf-=tmp;res+=tmp;e[i].flow-=tmp;e[e[i].op].flow+=tmp;
if(!maxf)break;
return res;
int sakura()int res=0;while(bfs())res+=dfs(S,INF);return res;
void makeSet(int x)for(int i=1;i<=x;i++)fa[i]=i;
int findSet(int x)return fa[x]==x?x:fa[x]=findSet(fa[x]);
void unionSet(int x,int y)int u=findSet(x),v=findSet(y);if(u^v)fa[u]=v;
bool cmp(int x,int y)return len[x]<len[y];
int main()
read(n);Tr.init();int summ=0;
for(int i=1;i<=n;i++)
bg[i]=ed[i-1]+1;scanf("%s",str+bg[i]);
len[i]=(int)strlen(str+bg[i]);ed[i]=bg[i]+len[i]-1;
for(int j=bg[i];j<=ed[i];j++)a[j]=str[j]-'a';
Tr.insert(bg[i],ed[i],i);summ+=len[i];
Tr.sakura();
for(int i=1;i<=n;i++以上是关于[CF590E]Birthday的主要内容,如果未能解决你的问题,请参考以下文章