[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的主要内容,如果未能解决你的问题,请参考以下文章

CF708DIncorrect Flow 最小费用可行流

上下界的网络流模板

[CF494D]Birthday

sgu176 有源汇上下界最小流

BZOJ 3876 支线剧情 | 有下界费用流

P4043 [AHOI2014/JSOI2014]支线剧情 上下界费用流