arc083F Collecting Balls

解析AtCoder上一道关于机器人收集球的问题,通过构建基环树和森林模型,运用组合数学方法,解决机器人如何有效收集球的问题,给出具体算法实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

https://arc083.contest.atcoder.jp/tasks/arc083_d

题意简述

n × n n\times n n×n的正方形上有 2 n 2n 2n个小球,第 i i i个在 ( x i , y i ) (x_i,y_i) (xi,yi)位置。有 n n n个A类机器人,第 i i i个在 ( 0 , i ) (0,i) (0,i)位置;有 n n n个B类机器人,第 i i i个在 ( i , 0 ) (i,0) (i,0)位置。依次启动机器人,A类机器人启动后将会向右走,将碰到的第 1 1 1个球收集起来,并不再启动;B类机器人启动后向上走,将碰到的第 1 1 1个求收集起来,并不再启动。求所有的方案中能收集所有小球的方案数模 1 0 9 + 7 10^9+7 109+7

题解

假设有 2 n 2n 2n个点,如果有位置为 ( x , y ) (x,y) (x,y)的球,那么将第 x x x个点和第 y + n y+n y+n个点连接起来,代表第 x x x个B类机器人和第 y y y个A类机器人才能取走这个球。最终形成了 2 n 2n 2n个点 2 n 2n 2n条边的图,对于每个连通块分别考虑。

假设这个连通块有 x x x个点,如果边数 ̸ = x \not= x ̸=x,显然方案数为0;否则必定存在一种方案使得点和边一一对应(就是点对应的机器人取走了边对应的球)。由于点数 = = =边数,因此这个连通块必定是一颗基环树。对于不在环上的点,只能存在一种方式对应边;对于环上的点,有两种方式对应边,枚举即可。

现在得到了每个机器人对应的球,显然,对应方向上坐标比它小的球都要被先取走。换句话说,就是这个机器人比其他的某些机器人后启动。将这个机器人向其他必须比他先启动的机器人连边。显然,所有连的边都是图上有的边,并且环上两个端点编号之和最大的边显然不会加入,因此连的边构成了一棵森林。

对于每个森林分别填数,要求父亲的权值比儿子大,设 f [ i ] f[i] f[i]表示 i i i的子树填数的方案数,显然
f [ i ] = ( s i z e [ i ] − 1 ) ! ∏ s ∈ s o n [ i ] s i z e [ s ] ! ∏ s ∈ s o n [ i ] f [ s ] f[i]=\frac{(size[i]-1)!}{\prod_{s\in son[i]} size[s]!}\prod _{s\in son[i]} f[s] f[i]=sson[i]size[s]!(size[i]1)!sson[i]f[s]
森林的方案数同理。

代码

#include <queue>
#include <cstdio>
#include <algorithm>

int read()
{
  int x=0,f=1;
  char ch=getchar();
  while((ch<'0')||(ch>'9'))
    {
      if(ch=='-')
        {
          f=-f;
        }
      ch=getchar();
    }
  while((ch>='0')&&(ch<='9'))
    {
      x=x*10+ch-'0';
      ch=getchar();
    }
  return x*f;
}

const int maxn=100000;
const int maxv=maxn*2;
const int maxe=maxv*2;
const int mod=1000000007;

std::queue<int> q;
std::vector<int> cur;
int n,pre[maxe+10],now[maxv+10],son[maxe+10],tot,_pre[maxe+10],_now[maxv+10],_son[maxe+10],_tot,vis[maxv+10],ecnt,cir[maxv+10],deg[maxv+10],choose[maxv+10],fac[maxv+10],ifac[maxv+10],f[maxv+10],size[maxv+10];

int C(int a,int b)
{
  return 1ll*fac[a]*ifac[b]%mod*ifac[a-b]%mod;
}

int _ins(int a,int b)
{
  _pre[++_tot]=_now[a];
  _now[a]=_tot;
  _son[_tot]=b;
  return 0;
}

int calc()
{
  for(auto i:cur)
    {
      deg[i]=_now[i]=0;
    }
  for(auto i:cur)
    {
      for(int j=now[i]; j; j=pre[j])
        {
          int v=son[j];
          if(v<choose[i])
            {
              _ins(v,i);
              ++deg[i];
            }
        }
    }
  for(auto i:cur)
    {
      if(!deg[i])
        {
          q.push(i);
        }
      f[i]=1;
      size[i]=1;
    }
  int sz=0,ans=1;
  while(!q.empty())
    {
      int u=q.front(),flag=0;
      q.pop();
      for(int i=_now[u]; i; i=_pre[i])
        {
          flag=1;
          int v=_son[i];
          --deg[v];
          size[v]+=size[u];
          f[v]=1ll*f[v]*f[u]%mod*C(size[v]-1,size[u])%mod;
          if(!deg[v])
            {
              q.push(v);
            }
        }
      if(!flag)
        {
          sz+=size[u];
          ans=1ll*ans*f[u]%mod*C(sz,size[u])%mod;
        }
    }
  return ans;
}

int ins(int a,int b)
{
  pre[++tot]=now[a];
  now[a]=tot;
  son[tot]=b;
  return 0;
}

int dfs(int u)
{
  vis[u]=1;
  cur.push_back(u);
  for(int i=now[u]; i; i=pre[i])
    {
      ++ecnt;
      int v=son[i];
      if(!vis[v])
        {
          dfs(v);
        }
    }
  return 0;
}

int search(int u)
{
  cir[++cir[0]]=u;
  vis[u]=1;
  for(int i=now[u]; i; i=pre[i])
    {
      int v=son[i];
      if(!vis[v])
        {
          search(v);
        }
    }
  return 0;
}

int solve()
{
  if((int)cur.size()!=ecnt)
    {
      return 0;
    }
  for(auto i:cur)
    {
      if(deg[i]==1)
        {
          q.push(i);
        }
    }
  while(!q.empty())
    {
      int u=q.front();
      q.pop();
      for(int i=now[u]; i; i=pre[i])
        {
          int v=son[i];
          if(deg[v]!=1)
            {
              --deg[v];
              choose[u]=v;
              if(deg[v]==1)
                {
                  q.push(v);
                }
            }
        }
    }
  int st=0;
  for(auto i:cur)
    {
      if(deg[i]>1)
        {
          st=i;
          vis[i]=0;
        }
    }
  cir[0]=0;
  search(st);
  cir[cir[0]+1]=cir[1];
  for(int i=1; i<=cir[0]; ++i)
    {
      choose[cir[i]]=cir[i+1];
    }
  int res=calc();
  for(int i=2; i<=cir[0]+1; ++i)
    {
      choose[cir[i]]=cir[i-1];
    }
  res+=calc();
  if(res>=mod)
    {
      res-=mod;
    }
  for(auto i:cur)
    {
      vis[i]=1;
    }
  return res;
}

int main()
{
  n=read();
  fac[0]=1;
  for(int i=1; i<=n<<1; ++i)
    {
      fac[i]=1ll*fac[i-1]*i%mod;
    }
  ifac[0]=ifac[1]=1;
  for(int i=2; i<=n<<1; ++i)
    {
      ifac[i]=1ll*(mod-mod/i)*ifac[mod%i]%mod;
    }
  for(int i=2; i<=n<<1; ++i)
    {
      ifac[i]=1ll*ifac[i-1]*ifac[i]%mod;
    }
  for(int i=1; i<=n<<1; ++i)
    {
      int x=read(),y=read();
      ins(x,y+n);
      ins(y+n,x);
      ++deg[x];
      ++deg[y+n];
    }
  int tsize=0,ans=1;
  for(int i=1; i<=n<<1; ++i)
    {
      if(!vis[i])
        {
          cur.clear();
          ecnt=0;
          dfs(i);
          ecnt/=2;
          int res=solve();
          tsize+=ecnt;
          ans=1ll*ans*res%mod*C(tsize,ecnt)%mod;
        }
    }
  printf("%d\n",ans);
  return 0;
}

s is a fascinating hobby for many people, particularly those interested in studying insects and their behavior. However, it's crucial to follow ethical and legal guidelines, and to ensure that bugs are collected and handled humanely. Here are some tips for collecting bugs: 1. Check local regulations: Before you start collecting bugs, check your local regulations to make sure it is legal to do so. Some areas may have restrictions on collecting certain species or collecting bugs in protected areas. 2. Use ethical and humane methods: It's important to use ethical and humane methods when collecting bugs. Avoid using harmful chemicals, and instead use gentle methods such as nets or traps. Handle the bugs carefully and avoid injuring them. 3. Respect the environment: When collecting bugs, make sure to respect the environment and the other creatures that live there. Avoid damaging plants or other habitats, and leave the area as you found it. 4. Keep accurate records: Keep accurate records of the species you collect, when and where you collected them, and any other relevant information. This can be helpful for scientific research and for tracking changes in insect populations over time. 5. Release the bugs: After you have collected and observed the bugs, release them back into their natural habitat. Make sure to do so in a safe and appropriate location, and handle them carefully to avoid injury. Remember that collecting bugs can be a fun and educational hobby, but it's important to do so responsibly and ethically. By following these guidelines, you can enjoy the hobby while also helping to protect these fascinating creatures and their habitats.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值