【2020牛客多校一:Ferrers 图】E:Counting Spanning Trees

E:Counting Spanning Trees

【Reference】

大神的Proof Paper

【难度】

7 / 10 7/10 7/10
结论题

【题意】

给一个二分图
左边有 n n n 个点,记作 x 1 , x 2 ⋯ x n x_1,x_2\cdots x_n x1,x2xn
右边有 m m m 个点,记作 y 1 , y 2 ⋯ y m y_1,y_2\cdots y_m y1,y2ym
给模数 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.ey1yai

让你求出取模后,最小生成树MST的数量

【数据范围】

1 ≤ n , m ≤ 1 0 5 1\le n,m\le 10^5 1n,m105
1 ≤ m o d ≤ 1 0 9 1\le mod\le 10^9 1mod109
1 ≤ a ≤ m 1\le a\le m 1am

【输入样例】

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 graphGU,VU={u0un}V={v0vm}(ui,vj)(up,vq)0pi,0qj(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=1nλpq=1     mλq λiiλi代表i节点的度λii

对于这题,我们通过差分数组简单计算出每个点的度数之后进行排序
度最大的两个点视为 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);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值