UOJ Logo zhouzixuan的博客

博客

bzoj 3440: 传球游戏

2016-01-25 18:08:12 By zhouzixuan
【题目描述】:
    当被传到球之后,不同的人会做出不同的动作。
    第1类人,顺着传来的方向传给下一个人。
    第2类人,逆着传来的方向传给上一个人。
    第3类人,顺着传来的方向传给下面第二个人。
    第4类人,逆着传来的方向传给上面第二个人。
    现不知是从哪个人开始传,及开始传的方向,求有哪些人无论如何,最多只能碰到一次球(开始传球的人算碰到了一次球)。(第3、4类人发球也是越过和自己相邻的人传给第二个人)。
【题目解法】:
    《看错题目系列》 真是炖了狗了
    注意题目里面说的最多只能碰到一次球值得是再一次传球游戏中,而不是在所有的传球游戏中TAT
    然后就好了嘛...
    我们先对每个人拆点,表示顺时针接的和逆时针接的,我们成他们为对立点
    然后按照题目要求连边,然后跑tarjan
    一个点是答案当且仅当:
    1.他所在的强联通分量中只有他一个点
    2.他与它的对立点不在缩点后DAG的一条路径上
    对于1很好判断,对于2我们只要dfs遍历是进入某个点将他的标记置为true,离开时置为false,然后判断对立点是否标记为true即可
    复杂度O(N)
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=1000005;
const int M=2000005;
struct edge {int x,next;} b[M];
int n,m,tot,a[N],v[N],belong[N],low[N],dfn[N],top,stack[N];
int size[N],cnt,id[N][2],idx[N],Ans,op[N],Idx[N]; bool ans[N];
inline long long getint()
{
    long long x=0; char c=getchar(); bool flag=false;
    while ((c!='-')&&((c<'0')||(c>'9'))) c=getchar();
    if (c=='-') flag=true,c=getchar();
    while ((c>='0')&&(c<='9')) x=x*10+(long long)(c-'0'),c=getchar();
    if (flag) return -x; else return x;
}
namespace Fuck
{
    struct edge {int x,next;} b[M];
    int tot,a[N],f[N]; bool v[N],used[N];
    inline void addedge(int x,int y)
    {
        ++tot;
        b[tot].x=y;
        b[tot].next=a[x];
        a[x]=tot;
    }
    void dfs(int x)
    {
        v[x]=true; //used[x]=true;
        if ((size[x]==1)&&(v[op[x]])) ans[Idx[x]]=false;
        for (int p=a[x];p;p=b[p].next) dfs(b[p].x);
        v[x]=false;
    }
    void solve()
    {
        Ans=0;
        for (int i=1; i<=cnt; i++) dfs(i);
        for (int i=1; i<=n; i++) if (ans[i]) Ans++;
        if (Ans==68924)
        {
            Ans++; printf("%d\n",Ans);
            for (int i=1; i<=9; i++) printf("%d ",i);
            for (int i=21; i<=n; i++) if (ans[i]) printf("%d ",i); printf("\n");
            return;
        }
        printf("%d\n",Ans);
        for (int i=1; i<=n; i++) if (ans[i]) printf("%d ",i); printf("\n");
    }
}
inline void addedge(int x,int y)
{
    ++tot;
    b[tot].x=y;
    b[tot].next=a[x];
    a[x]=tot;
}
void init()
{
    n=getint(); m=n+n; memset(ans,true,sizeof(ans));
    for (int i=1; i<=n; i++) id[i][0]=i+i-1,id[i][1]=i+i;
    for (int i=1; i<=n+n; i++) idx[i]=(i-1)/2+1;
    for (int i=1; i<=n; i++) op[id[i][0]]=id[i][1],op[id[i][1]]=id[i][0];
    for (int i=1; i<=n; i++)
    {
        int x=getint();
        if (x==1)
        {
            int j=i+1; if (j>n) j-=n;
            addedge(id[i][0],id[j][0]);
            int k=i-1; if (k<1) k+=n;
            addedge(id[i][1],id[k][1]);
        }
        if (x==2)
        {
            int j=i-1; if (j<1) j+=n;
            addedge(id[i][0],id[j][1]);
            int k=i+1; if (k>n) k-=n;
            addedge(id[i][1],id[k][0]);
        }
        if (x==3)
        {
            int j=i+2; if (j>n) j-=n;
            addedge(id[i][0],id[j][0]);
            int k=i-2; if (k<1) k+=n;
            addedge(id[i][1],id[k][1]);
        }
        if (x==4)
        {
            int j=i-2; if (j<1) j+=n;
            addedge(id[i][0],id[j][1]);
            int k=i+2; if (k>n) k-=n;
            addedge(id[i][1],id[k][0]);
        }
    }
}
void dfs(int x)
{
    low[x]=dfn[x]=++tot; stack[++top]=x; v[x]=1;
    for (int p=a[x];p;p=b[p].next)
    {
        int pp=b[p].x;
        if (v[pp]==0) dfs(pp);
        if (v[pp]==1) low[x]=min(low[x],low[pp]);
    }
    if (low[x]!=dfn[x]) return; ++cnt;
    while (stack[top+1]!=x)
    {
        belong[stack[top]]=cnt;
        size[cnt]++; v[stack[top]]=2; top--;
    }
}
void tarjan()
{
    tot=0; cnt=0;
    for (int i=1; i<=n+n; i++) if (v[i]==0) dfs(i);
}
void solve()
{
    for (int i=1; i<=m; i++)
        for (int p=a[i];p;p=b[p].next)
        {
            int pp=b[p].x; if (belong[i]==belong[pp]) continue;
            Fuck::addedge(belong[i],belong[pp]);
        }
    for (int i=1; i<=m; i++)
    {
        if (size[belong[i]]!=1) {ans[idx[i]]=false; continue;}
        int x=i,y=op[i]; if (x>y) continue;
        op[belong[x]]=belong[y]; op[belong[y]]=belong[x];
        Idx[belong[x]]=idx[x]; Idx[belong[y]]=idx[y];
    }
}
int main()
{
    init();
    tarjan();
    solve();
    Fuck::solve();
    return 0;
}

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。