题意:有$N$个球,有颜色$c_i$,重量$w_i$,若($c_a=c_b$且$w_a+w_b\leq X$)或($c_a\ne c_b$且$w_a+w_b\leq Y$),可以交换$a,b$,求总共可以得到多少种不同的颜色序列
首先我们当然要比较快地找到哪些球是可以交换的
因为交换具有传递性,所以我们构造一个图:若$i$和$j$可以交换,他们之间有至少一条路径
先看颜色相同
设$m_i$表示颜色为$i$的球中重量最小的球
那么对于每一个球$k$,只需要考虑$w_k+w_{m_{c_k}}\leq X$即可,因为所有球都与最轻的相连,他们也就自然连通了
再看颜色不同
设$m_i$中重量最小的球为$a$,重量次小的球为$b$
那么对于每一个球$k$,只需要考虑$w_k+w_a\leq Y$或$w_k+w_b\leq Y$即可
假证明:对于任意$s,t(w_s+w_t\leq Y)$
若$c_s\ne c_a$且$c_t\ne c_a$,交换方式:$s\Leftrightarrow a\Leftrightarrow t$
若$c_s\ne c_b$且$c_t\ne c_b$,交换方式:$s\Leftrightarrow b\Leftrightarrow t$
若$\{c_s,c_t\}=\{c_a,c_b\}$,交换方式:$s\Leftrightarrow a\Leftrightarrow b\Leftrightarrow t$
于是我们得到哪些球可以随意交换,现在要算方案数
若有$m$种颜色,第$i$种颜色的数量为$v_i$
我们按顺序把每种颜色gay进去
轮到第$i$种颜色时,有$v_i+\cdots+v_m$个空位,方案数为$C_{v_i}^{v_i+\cdots+v_m}$
于是总方案数为$C_{v_1}^{v_1+\cdots+v_m}\cdot C_{v_2}^{v_2+\cdots+v_m}\cdot\cdots\cdot C_{v_m}^{v_m}$
都是$n$的级别,直接预处理阶乘暴力算即可
#include<stdio.h>
#define mod 1000000007ll
#define inf 2147483647ll
#define ll long long
struct edge{
int to,nex;
}e[3000010];
int c[200010],h[200010],pos[200010],cnt[200010],tot;
ll w[200010],fac[200010],rfac[200010],min[200010];
bool v[200010];
ll pow(ll a,ll b){
ll ans=1,base=a;
while(b){
if(b&1)ans=(ans*base)%mod;
base=(base*base)%mod;
b>>=1;
}
return ans;
}
ll C(ll n,ll k){
return(((fac[n]*rfac[n-k])%mod)*rfac[k])%mod;
}
void add(int a,int b){
tot++;
e[tot].to=b;
e[tot].nex=h[a];
h[a]=tot;
}
void dfs(int x){
v[x]=1;
for(int i=h[x];i;i=e[i].nex){
if(!v[e[i].to])dfs(e[i].to);
}
}
int main(){
int n,i,fir,sec=0;
ll X,Y,min1,min2,tot,ans;
scanf("%d%lld%lld",&n,&X,&Y);
fac[0]=1;
for(i=1;i<=n;i++){
scanf("%d%lld",c+i,w+i);
fac[i]=(i*fac[i-1])%mod;
min[i]=inf;
}
rfac[n]=pow(fac[n],mod-2);
for(i=n;i>0;i--)rfac[i-1]=(i*rfac[i])%mod;
for(i=1;i<=n;i++){
if(w[i]<min[c[i]]){
min[c[i]]=w[i];
pos[c[i]]=i;
}
}
for(i=1;i<=n;i++){
if(i!=pos[c[i]]&&w[i]+min[c[i]]<=X){
add(i,pos[c[i]]);
add(pos[c[i]],i);
}
}
min1=min2=inf;
for(i=1;i<=n;i++){
if(w[i]<min1){
min1=w[i];
fir=i;
}
}
for(i=1;i<=n;i++){
if(w[i]<=min2&&c[i]!=c[fir]){
min2=w[i];
sec=i;
}
}
for(i=1;i<=n;i++){
if(i==fir)continue;
if(c[i]!=c[fir]&&w[i]+w[fir]<=Y){
add(i,fir);
add(fir,i);
}
if(sec&&c[i]!=c[sec]&&w[i]+w[sec]<=Y){
add(i,sec);
add(sec,i);
}
}
dfs(fir);
tot=0;
for(i=1;i<=n;i++){
if(v[i]){
tot++;
cnt[c[i]]++;
}
}
ans=1;
for(i=1;i<=n;i++){
if(cnt[i]){
ans=(ans*C(tot,cnt[i]))%mod;
tot-=cnt[i];
}
}
printf("%lld",ans);
}