[Luogu P5676][GZOI2017]小z玩游戏

(GZOI2017D1T2)

题目链接?不存在的 Luogu P5676 [GZOI2017]小z玩游戏

题面

做了半天一直不对,交一发就A了?样例出锅了吧。。(Luogu的样例是改过的,如果有错请联系我qwq)

很显然对每个兴奋程度向能玩的游戏连边,游戏向相应的兴奋程度连边,然后问题转化为有多少游戏在一个环上,且能被兴奋程度为(1)的节点到达

但是直接连边是(O(n^2))的,显然不行,需要优化。

(N=100000)

(N)个点(1sim N)表示当前兴奋程度

(N)个点(N+1sim 2N)为中转节点

(N)个点(2N+1sim 3N)表示(N)款游戏

那么对于(1le i,jle N,i|j),连边((i,N+j)),表示兴奋程度(i)能玩有趣程度为(j)的游戏

对于(1le ile n),连边((N+w_i,2N+i),(2N+i,e_i)),表示第(i)款游戏有趣程度为(w_i),玩完后兴奋程度变为(e_i)

那么连边的复杂度就是喜闻乐见的调和级数:(sum_{i=1}^Nlimits frac Ni=O(Nlog N))

接着跑一遍Tarjan,DFS一边求出哪些强连通分量可以被初始点达到

然后判断一下就好了,注意大小为(1)的强连通分量不是环。

时间复杂度 (O(TNlog N))

空间复杂度 (O(Nlog N))

代码:

#include <cstdio>
#include <cctype>
#include <cstring>

inline int Min(const int a,const int b){return a<b?a:b;}
inline int Max(const int a,const int b){return a>b?a:b;}
#define Getchar (p1==p2&&(p2=(p1=In)+fread(In,1,1<<22,stdin),p1==p2)?EOF:*p1++)
char In[1<<22],*p1=In,*p2=In,Ch;
inline int Getint(int x=0)
{
    while(!isdigit(Ch=Getchar));
    for(;isdigit(Ch);Ch=Getchar)x=x*10+(Ch^48);
    return x;
}

const int N=100000,V=N*3+5,E=N*14;
int T,n,w[N+5],Ans;
int Dfn[V],Low[V],Tim,Ins[V],Sta[V],Top;
int Dcc[V],Siz[V],Dn,Deg[V],Vis[V];
struct Graph
{
    int Head[V],Next[E],To[E],En;
    inline void Clear(){memset(Head,En=0,sizeof Head);}
    inline void Add(int x,int y){Next[++En]=Head[x],To[Head[x]=En]=y;}
}G1,G2;

void Tarjan(int x)
{
    Dfn[x]=Low[x]=++Tim,Ins[Sta[++Top]=x]=1;
    for(int i=G1.Head[x],y;i;i=G1.Next[i])
        if(!Dfn[y=G1.To[i]])Tarjan(y),Low[x]=Min(Low[x],Low[y]);
        else if(Ins[y])Low[x]=Min(Low[x],Dfn[y]);
    if(Low[x]==Dfn[x])
    {
        int y=++Dn;
        do Ins[y=Sta[Top--]]=0,Dcc[y]=Dn,++Siz[Dn];
        while(y!=x);
    }
}

void DFS(int x){if(!Vis[x]){Vis[x]=1;for(int i=G2.Head[x];i;i=G2.Next[i])DFS(G2.To[i]);}}

int main()
{
    freopen("in.txt","r",stdin);
    for(T=Getint();T--;printf("%d
",Ans))
    {
        G1.Clear(),G2.Clear(),n=Getint(),Ans=0;
        for(int i=1;i<=N;++i)
            for(int j=i;j<=N;j+=i)
                G1.Add(i,N+j);
        for(int i=1;i<=n;++i)G1.Add(N+(w[i]=Getint()),N*2+i);
        for(int i=1;i<=n;++i)G1.Add(N*2+i,Getint());
        memset(Dfn,0,sizeof Dfn),memset(Siz,0,sizeof Siz),Tim=Dn=0;
        for(int i=1;i<=3*N;++i)if(!Dfn[i])Tarjan(i);
        memset(Deg,0,sizeof Deg),memset(Vis,0,sizeof Vis);
        for(int i=1,t;i<=3*N;++i)
            for(int j=G1.Head[i];j;j=G1.Next[j])
                if(Dcc[i]!=(t=Dcc[G1.To[j]]))
                    G2.Add(Dcc[i],t),++Deg[t];
        DFS(Dcc[1]);
        for(int i=1;i<=n;++i)
            if(Vis[Dcc[N*2+i]]&&Siz[Dcc[N*2+i]]>1)
                ++Ans;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/LanrTabe/p/11896300.html