传送门

题目大意

给定$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. Spring boot cassandra - nested exception is com.datastax.driver.core.exceptions.NoHostAvailableException

    1.在Pom.xml添加spring-boot-starter-data-cassandra依赖: <dependency> <groupId>org.springframew ...

  2. Python之内置函数再总结

    一.数字相关 1.绝对值:abs(-1) 2.最大最小值:max([1,2,3]) ,min([1,2,3]) 3.序列长度:len('abc')  ,  len([1,2,3])  ,  len(( ...

  3. NavigationDrawer和NavigationView-Android M新控件

    Translucent System Bars-4.4新特性 Toolbar-5.0新特性 NavigationDrawer 简介 NavigationDrawer 是 Google 在 Materi ...

  4. 自己动手编译Android源码(超详细)

    http://www.jianshu.com/p/367f0886e62b 在Android Studio代码调试一文中,简单的介绍了代码调试的一些技巧.现在我们来谈谈android源码编译的一些事. ...

  5. PHP封装时间类

    开发中经常用到时间的一些操作,比如昨天,今天,前天,近七天,一周等等. class time{ private $year;//年 private $month;//月 private $day;// ...

  6. 超酷Loading进度条

    在线演示 本地下载

  7. iOS 学习之 UITabBarController

    - (IBAction)btnClick:(id)sender { UITabBarController *tabBarCtrl = [[[UITabBarController alloc] init ...

  8. iOS下的WiFi开发

    iOS下Wi-Fi开发需要添加依赖库SystemConfiguration.framework,在需要使用Wi-Fi信息的控制器下引入头文件#import <SystemConfiguratio ...

  9. 在各种Linux发行版上安装Git的教程

    Git是一个流行的开源版本控制系统(VCS),最初是为Linux环境开发的.跟CVS或者SVN这些版本控制系统不同的是,Git的版本控制被认为是“分布式的”,某种意义上,git的本地工作目录可以作为一 ...

  10. Kafaka高可用集群环境搭建

    zk集群环境搭建:https://www.cnblogs.com/toov5/p/9897868.html 三台主机每台的Java版本1.8 下面kafka集群的搭建:  3台虚拟机均进行以下操作:  ...