传送门

题目大意

给定$N$,在$(1,0),(2,0)......(N,0)$和$(0,1),(0,2)...(0,N)$上都有$1$个机器人,同时给定$2N$个坐标$(x,y),x,y\in[1,N]$上有障碍,你每次可以选择一个没有被选过的机器人$K$,若$X_K=0$,则它会沿着$y$轴正方向移动直到遇到遇到障碍或移出边界$[0,N]$,若它遇到障碍,则它会和障碍一同消失。

求选择$2N$个机器人的$(2N!)$中顺序中,有多少种会使得所有障碍消失。

题解

神仙题

考虑把每一行和每一列看做$2N$个点,对于障碍$(x,y)$,视为在$x$行$y$列之间连一条边。

显然,一条边只能被它的两个端点删掉,同一,一个点端点只能用于删掉一个条边。

那么对于每一个连通块,当且仅当它是一个基环树时才可能有解。

考虑树边,显然叶子节点只能删掉连接它的边,那么同理可得树边只能被距离环更远的端点删掉。

而环上的边也只有两种情况,每个点要么顺时针删去下一条边,要么逆时针删去下一条边,枚举即可。

假设我们已经确定了每个点删掉了哪条边。

假设我们用$x$点删掉了$(x,y)$,那么考虑$y$是$(x,y)$的另一维坐标,那么对于$x$连接的$k$,若$k<y$,删除$(x,y)$之前一定要先删除$(x,k)$,所以$k$一定要在$x$之前先选,可以再建一个图,新图中$k$向$x$连边。

于是我们就得到了一个有先后顺序要求的拓扑图。显然这是一个森林,因为对于任意点对$(a,b)$,一定不会存在两种方式从$a$到达$b$,而且新图上的边在原图中一定是从树枝的叶子一步步连向环的某一个节点,所以森林是若干颗内向树构成的。

考虑有$m$个点的内向树有多少种拓扑序。共有$m!$中排序方式,其中对于以$x$为根的子树,它可能是拓扑序当且仅当它是这$Size_x$个节点中($Size_x$表示其子树大小)的最后一个(在外向树中应该是第一个,所以有向树在去掉方向后同构则拓扑序数量),那么它是有效的序列只有$\frac{1}{Size_x}$种,每一棵子树可以独立考虑,所以拓扑序方案数就是$\frac{m!}{\prod\limits_{x=1}^{m} Size_x}$。

对于一棵内向树森林,则$Size$定义不变,$m$变为森林中所有点的点数。

由于环上的选边方式有两种,就枚举方向再加起来,就得到了消完这个连通块的方案数。

对于连通块$i$,设其点数为$m_i$,方案数为$Ans_i$,一共有$K$个连通块。

最后的总方案数是$$\prod\limits_{i=1}^{K}\dbinom{\sum\limits_{j=i}^{K}m_j}{m_i}\times Ans_i$$

虽然已经可以算了,但是我们还可以通过把$\dbinom{n}{m}$化为$\frac{n!}{m!(n-m)!}$的形式,不难发现这个上式就变成了$$\frac{(2N)!}{\prod\limits_{i=1}^{K}m_i}\prod\limits_{i=1}^{K}Ans_i$$更加直观且容易计算。

复杂度$O(n)$。

#include<bits/stdc++.h>
#define LL long long
#define M 200020
#define mod 1000000007
using namespace std;
namespace IO{
const int BS=(1<<22)+5; int Top=0;
char Buffer[BS],OT[BS],*OS=OT,*HD,*TL,SS[20]; const char *fin=OT+BS-1;
inline char Getchar(){if(HD==TL){TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);} return (HD==TL)?EOF:*HD++;}
inline void write(int x){
if(!x){putchar('0');return;} if(x<0) x=-x,putchar('-');
while(x) SS[++Top]=x%10,x/=10;
while(Top) putchar(SS[Top]+'0'),--Top;
}
inline int read(){
int nm=0; char cw=Getchar(); for(;!isdigit(cw);cw=Getchar());
for(;isdigit(cw);cw=Getchar()) nm=nm*10+(cw-'0'); return nm;
}
}
using namespace IO;
#define mul(x,y) (LL)(x)*(y)%mod
#define upd(x,y) x=((x)+(y)>=mod)?(x)+(y)-mod:(x)+(y)
int n,m,fs[M],nt[M<<1],to[M<<1],tmp,ans=1,EG,top,ind[M],node[M];
int S[M],c[M],fa[M],nxt[M],fst[M],tar[M],cur,cnt,sz[M],inv[M],vis[M];
inline void link(int x,int y){
nt[tmp]=fs[x],fs[x]=tmp,to[tmp++]=y;
nt[tmp]=fs[y],fs[y]=tmp,to[tmp++]=x;
}
inline void edge(int x,int y){nxt[cur]=fst[x],fst[x]=cur,tar[cur++]=y;}
void init(int x,int last){
node[++cnt]=x,S[++top]=x,ind[x]=1,S[top+1]=0;
for(register int i=fs[x];~i;i=nt[i],EG++){
if(to[i]==last) continue;
if(!ind[to[i]]){init(to[i],x);continue;}
if(m) continue;
while(S[top+1]!=to[i]) vis[c[++m]=S[top--]]=true; c[0]=to[i];
} top--,ind[x]=2;
}
void build(int x,int last){
for(register int i=fs[x];~i;i=nt[i]){
if(vis[to[i]]||to[i]==last) continue;
fa[to[i]]=x,build(to[i],x);
}
}
int dfs(int x){
if(sz[x]) return 1; int res=sz[x]=1;
for(register int i=fst[x];i!=-1;i=nxt[i]){
res=mul(res,dfs(tar[i])),sz[x]+=sz[tar[i]];
} return mul(res,inv[sz[x]]);
}
inline int calc(){
for(int i=1;i<=cnt;i++) fst[node[i]]=-1,sz[node[i]]=0; cur=0; int res=1;
for(int x=1;x<=cnt;x++) for(register int i=fs[node[x]];i!=-1;i=nt[i]) if(to[i]<fa[node[x]]) edge(node[x],to[i]);
for(int x=1;x<=cnt;x++) if(!sz[node[x]]) res=mul(res,dfs(node[x])); return res;
}
inline int solve(int x){
top=0,init(x,0); if(EG!=(cnt<<1)) puts("0"),exit(0);
for(int i=1;i<=m;i++) build(c[i],0); int res=0;
for(int i=1;i<=m;i++) fa[c[i-1]]=c[i]; upd(res,calc());
for(int i=1;i<=m;i++) fa[c[i]]=c[i-1]; upd(res,calc());
return res;
}
int main(){
n=read(),ans=inv[1]=1,memset(fs,-1,sizeof(fs));
for(int i=2;i<=(n<<1);i++) ans=mul(ans,i),inv[i]=mul(inv[mod%i],mod-(mod/i));
for(int i=1;i<=(n<<1);i++) link(read()+n,read());
for(int i=1;i<=(n<<1);i++) if(!ind[i]) cnt=m=EG=0,ans=mul(ans,solve(i));
printf("%d\n",ans); return 0;
}

Arc083_F Collecting Balls的更多相关文章

  1. [ARC083F] Collecting Balls [建二分图+环套树定向+建拓扑图+树的拓扑序计数]

    题面 [传送门](https://arc083.contest.atcoder.jp/tasks/arc083_d) 思路 这是一道真正的好题 第一步:转化模型 行列支配类的问题,常见做法就是把行和列 ...

  2. 【AtCoder Beginner Contest 074 B】Collecting Balls (Easy Version)

    [链接]h在这里写链接 [题意] 看懂题目之后就会发现是道大水题. [题解] 在这里写题解 [错的次数] 0 [反思] 在这了写反思 [代码] #include <bits/stdc++.h&g ...

  3. 题解-AtCoder ARC-083F Collecting Balls

    Problem ARC083F 题意概要:给定 \(2n\) 个二维平面上的球,坐标分别为 \((x_i,y_i)\),并给出 \(n\) 个 \(A\)类 机器人 和 \(n\) 个 \(B\)类 ...

  4. [ARC083]Collecting Balls

    Description 有一个 \(n\times n\) 的矩阵,矩阵内有 \(2n\) 个球.对于 \(i \in [1,n]\) ,\((0,i) (i,0)\) 的位置各有一个启动后往右走/往 ...

  5. [atARC083F]Collecting Balls

    考虑一个构造,对于坐标$(x,y)$,连一条$x$到$y$的边(注意:横坐标和纵坐标即使权值相同也是不同的点),之后每一个连通块独立,考虑一个连通块内部: 每一个点意味着一次删除操作,每一个边意味着一 ...

  6. Atcoder 乱做

    最近感觉自己思维僵化,啥都不会做了-- ARC103 F Distance Sums 题意 给定第 \(i\) 个点到所有点的距离和 \(D_i\) ,要求构造一棵合法的树.满足第 \(i\) 个点到 ...

  7. 【AtCoder】ARC083

    C - Sugar Water 计算一下可以达到水是多少,可以到达的糖是多少 枚举水,然后加最多能加的糖,是\(min(F - i *100,E * 100)\),计算密度,和前一个比较就行 #inc ...

  8. AtCoder刷题记录

    构造题都是神仙题 /kk ARC066C Addition and Subtraction Hard 首先要发现两个性质: 加号右边不会有括号:显然,有括号也可以被删去,答案不变. \(op_i\)和 ...

  9. POJ2096 Collecting Bugs

    Time Limit: 10000MS   Memory Limit: 64000K Total Submissions: 5090   Accepted: 2529 Case Time Limit: ...

随机推荐

  1. 使用PLSQL Developer和DbVisualizer、SQLDBx查询oracle数据库时出现乱码

    使用PLSQL Developer和DbVisualizer查询oracle数据库时,出现查询数据中文乱码情况. 查看了一下数据库编码格式select * from v$nls_parameters; ...

  2. 分布式计算开源框架Hadoop入门实践(一)

    在SIP项目设计的过程中,对于它庞大的日志在开始时就考虑使用任务分解的多线程处理模式来分析统计,在我从前写的文章<Tiger Concurrent Practice --日志分析并行分解设计与实 ...

  3. 【转】Python爬虫(4)_selenium模块

    一 介绍 selenium最初是一个自动化测试工具,而爬虫中使用它主要是为了解决requests无法直接执行JavaScript代码的问题 selenium本质是通过驱动浏览器,完全模拟浏览器的操作, ...

  4. 合并apk和odex 为完整的apk安装文件

    from:http://bbs.hiapk.com/thread-1151284-1-1.html 文件夹:<ignore_js_op> 文件夹拖放到odex.cmd,出现下面的窗口后,按 ...

  5. SourceTree的基本使用---团队开发/参与开源

    1.实践入门-团队开发 如果你看到第二部分关于“参与开源”的内容,而你的需求是团队开发,你会发现几个不方便的地方: 1.1.组长建项目,组员每次提交,都需要组长审查同意merge 如果你觉得麻烦,组长 ...

  6. java MD5Utils 加密工具类

    package com.sicdt.library.core.utils; import java.io.File; import java.io.FileInputStream; import ja ...

  7. 【转载】OpenWrt sysupgrade 命令行更新固件到最新版

    OpenWrt sysupgrade 命令行更新固件到最新版 下面我们要使用 sysupgrade 更新固件到trunk最新版. 要注意的是,trunk包含试验的功能,可能不稳定,刷机风险自己承担. ...

  8. arguments解析

    js中并没有函数重载的概念,但函数的arguments参数能帮助我们模拟重载. arguments并不是真正的数组,但拥有length(参数数目),且能通过数组下标的方式进行访问,例如argument ...

  9. 20145210姚思羽《网络对抗》MSF基础应用实验

    20145210姚思羽<网络对抗>MSF基础应用实验 实验后回答问题 1.用自己的话解释什么是exploit,payload,encode. exploit就是进行攻击的那一步 paylo ...

  10. hdu1010感想

    杭电这道题是用dfs走迷宫问题,一直wa是因为没有将走过的地方标记,所以如果遇到走迷宫的问题一定要将走过的地方标记,如下: &&nx<n&&ny>=& ...