【Reference】
【难度】
7
/
10
7/10
7/10
结论题
【题意】
给一个二分图
左边有
n
n
n 个点,记作
x
1
,
x
2
⋯
x
n
x_1,x_2\cdots x_n
x1,x2⋯xn
右边有
m
m
m 个点,记作
y
1
,
y
2
⋯
y
m
y_1,y_2\cdots y_m
y1,y2⋯ym
给模数
M
O
D
MOD
MOD
对于
x
i
x_i
xi ,它连接了右侧前
a
i
a_i
ai 个节点
i
.
e
y
1
⋯
y
a
i
i.e\quad y_1\cdots y_{a_i}
i.ey1⋯yai
让你求出取模后,最小生成树MST的数量
【数据范围】
1
≤
n
,
m
≤
1
0
5
1\le n,m\le 10^5
1≤n,m≤105
1
≤
m
o
d
≤
1
0
9
1\le mod\le 10^9
1≤mod≤109
1
≤
a
≤
m
1\le a\le m
1≤a≤m
【输入样例】
n
,
m
,
m
o
d
n,m,mod
n,m,mod
a
i
,
⋯
,
a
n
a_i,\cdots,a_n
ai,⋯,an
2 1 1000000000
1 1
2 2 1000000000
2 2
3 3 1000000000
1 2 3
【样例输出】
1
4
4
【思路】
对于结论题,我们只有两种做法!
(1)自己证明出来! (这辈子都不可能的)
(2)看过paper后记住!
【以下内容均参考了大神paper,链接见上】
我
们
定
义
F
e
r
r
e
r
s
g
r
a
p
h
,
首
先
它
是
一
个
二
分
图
,
G
两
个
顶
点
划
分
U
,
V
为
U
=
{
u
0
⋯
u
n
}
V
=
{
v
0
⋯
v
m
}
那
么
:
∙
如
果
(
u
i
,
v
j
)
是
一
条
边
,
那
么
(
u
p
,
v
q
)
也
是
一
条
边
,
对
于
所
有
的
0
≤
p
≤
i
,
0
≤
q
≤
j
都
成
立
∙
(
u
0
,
v
m
)
和
(
u
n
,
v
m
)
也
是
边
我们定义\pmb{Ferrers\ graph},首先它是一个二分图,G两个顶点划分U,V为\\ U=\{u_0\cdots u_n\}\\ V=\{v_0\cdots v_m\}\\ \begin{aligned} &那么:\\ &\bullet 如果(u_i,v_j)是一条边,那么(u_p,v_q)也是一条边,对于所有的0\le p\le i,0\le q\le j都成立\\ &\bullet (u_0,v_m)和(u_n,v_m)也是边 \end{aligned}\\ \ \\
我们定义Ferrers graphFerrers graphFerrers graph,首先它是一个二分图,G两个顶点划分U,V为U={u0⋯un}V={v0⋯vm}那么:∙如果(ui,vj)是一条边,那么(up,vq)也是一条边,对于所有的0≤p≤i,0≤q≤j都成立∙(u0,vm)和(un,vm)也是边
那 么 G 的 最 小 生 成 树 的 数 量 为 : τ ( G ) = ∏ n p = 1 λ p ⋅ ∏ m λ q ′ q = 1 其 中 λ i 代 表 i 节 点 的 度 那么G的最小生成树的数量为:\\ \tau(G)=\underset{p=1}{\overset{n}{\prod}}\lambda_p·\underset{q=1\ \ \ \ \ }{\overset{m}{\prod}\lambda_q'}\\ \ \\ 其中\pmb{\lambda_i代表i节点的度} 那么G的最小生成树的数量为:τ(G)=p=1∏nλp⋅q=1 ∏mλq′ 其中λi代表i节点的度λi代表i节点的度λi代表i节点的度
对于这题,我们通过差分数组简单计算出每个点的度数之后进行排序
度最大的两个点视为
u
0
,
v
0
u_0,v_0
u0,v0,我们不把他们的度乘进答案即可。
【核心代码(出自队友禾硕)】
const int MAXN = 1e5 + 50;
#define mem(a,x) memset(a,x,sizeof(a))
ll n,m,mo;
ll a[MAXN],b[MAXN];
int main()
{
while(scanf("%lld%lld%lld",&n,&m,&mo) + 1)
{
ll ans = 1;
mem(b,0);
for(int i = 1;i <= n;i ++)scanf("%lld",&a[i]),b[a[i]] ++;
for(int i = m - 1;i;i --)b[i] += b[i + 1];
sort(a + 1,a + 1 + n);
sort(b + 1,b + 1 + m);
for(int i = 1;i < n;i ++)ans = ans * a[i] % mo;
for(int i = 1;i < m;i ++)ans = ans * b[i] % mo;
printf("%lld\n",ans);
}
}