牛客网 【每日一题】4月10日 二分图染色(弱化版)
精講 組合、容斥
文章目錄
- 題目:
- 題意&&題解::
- 代碼:
題目傳送
題目:
時間限制:C/C++ 1秒,其他語言2秒
空間限制:C/C++ 524288K,其他語言1048576K
64bit IO Format: %lld
題目描述
給定一個完全二分圖,圖的左右兩邊的頂點數(shù)目相同。我們要給圖中的每條邊染成紅色、藍色、或者綠色,并使得任意兩條紅邊不共享端點、同時任意兩條藍邊也不共享端點。
計算所有滿足條件的染色的方案數(shù),并對109+7取模。 (ps:本題數(shù)據(jù)量與實際比賽中數(shù)據(jù)量相比,少了一些)
輸入描述:
二分圖單邊的頂點數(shù)目n(n ≤ 10^7)
輸出描述:
輸出一個整數(shù),即所求的答案。
示例1
輸入
輸出
35題意&&題解::
完全二分圖:是一種特殊的二分圖,可以把圖中的頂點分成兩個集合,使得第一個集合中的所有頂點都與第二個集合中的所有頂點相連。
我們可以把左右各有n個點的二分圖的題轉(zhuǎn)化成n*n的棋盤問題。(離散上學過)
題目:讓染三個顏色,紅藍綠,但是綠色并沒有什么要求,我們可以最后再隨便放。所以我們先考慮紅和藍。
紅和藍都是不能共享端點,同步到棋盤上(行和列分別表示二分圖兩個集合),也就是棋盤上行和列只能有一個紅或藍
現(xiàn)在的題目就是:
在n*n的棋盤上,放任意紅和藍棋子,任一行和列不能有相同顏色的棋子,有多少種放的方法?
Fn表示棋盤大小為 n * n時的答案
先只考慮一個顏色: Fn=種方案(先在n行里選若干行,然后每一行選若干列,行沒有順序區(qū)分,就是選兩行,選第一行和第三行與選第一行和第二行沒差,所以選行用組合;而列不一樣,因為行列只能放一個,我們可以先放在一行上,然后分散到其他行,所以選列的時候要考慮順序問題,要用的是排列而不是組合)
如圖:
比如我們選兩行(C2 n ),然后每行放一個,我們先考慮都放在一行上,看圖中最上面兩行(黃色和綠色),都是選的第一個格和第二個格,但是分散開不一樣,(圖中4 * 4的表格)說明我們要考慮順序,所以選列是A2n,將所以情況加起來就是選一個顏色的方案
選兩個顏色:從上面我們能得到一個顏色是Fn,兩個就是Fn* Fn,非也,因為這樣會出現(xiàn)一個格子放兩個棋子,我們還要將這種情況刪去。需要容斥。
我們用gi表示最少有i個點放了兩個棋子(顏色不一樣)的方案數(shù)。那么除去i 行和i 列(i個點所在),我們在剩下n-i行與列里就不會有重復的,gi = f 2n-i 。被除去的 i 行與 i列選法和之前一樣是 CinAin ,最后得到容斥公式:
(這一部分好好理解)
CknAkn都可以求好,但是Fn提前求會超時,說明上面的公式不能用,我們要換一個想法來求
我們來考慮Fn能不能遞推出來,從Fn-1推出Fn
考慮n-1到n的過程:
一共增加了2n-1個格子(n2-(n-1)2),n-1之前的格子都已經(jīng)放好了,我們只需要考慮多出的這些格子該怎么放。
如果只放一個棋子,就有2n-1個方案,如果都不放,一個方案,一共是2n種方案,也就是2nFn-1,(Fn-1是之前n-1行列已經(jīng)放好的方案數(shù))
但是有限制條件,每一行不能有相同顏色,每放一個棋子,意味著這一行這一列都不能放了,就會出現(xiàn)n-1種重復情況(因為是從n-1的擴展來的),我們之前n-1行列的棋子都平移靠邊,因為之前都是不同行同列,所以靠邊后,正好占了一行一列,也就是我們在新增部分可以放的棋子,實際上是Fn-2而非Fn-1(這里可以看看圖),那一共(n-1)Fn-2次重復情況,可以選n-1行,而且每一列也可以進行相同操作,總的方案數(shù)就是2×(n?1) 2 ?F(n?2)
借鑒鄧老師的圖:
我們還要考慮放兩個的情況;
即最后一行和列分別放一個,這樣不重復嘛
方案就是:(n-1)2F(n-2)
總結(jié):得到公式
F[n]=2nF[n-1]-(n-1)2F[n-2]
(我真的是把我所能理解都寫出來了 )
代碼:
#include<cstdio> #include<iostream> #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 10000004; const int mod = 1e9 + 7;int g[N],s[N],F[N]; ll C(int n,int m) {return 1ll * g[n] * s[m] % mod * s[n - m] % mod; } ll A(int n,int m) {return 1ll * g[n] * s[n - m] % mod; } int main() {cin>>n;g[0] = 1;for(int i = 1;i <= n;++i)g[i] = 1ll * g[i - 1] * i % mod;ll ans1 = 1;for(;y;y >>= 1,x = x * x % mod){if(y & 1) ans1 = ans1 * x % mod;}s[n] = ans1;for(int i = n - 1;i >= 0;--i)s[i] = 1ll * s[i + 1] * (i + 1) % mod;F[0] = 1;F[1] = 2;for(int i = 2;i <= n;++i)F[i] = (2ll * i * F[i - 1] - 1ll * F[i - 2] * (i - 1) % mod * (i - 1) % mod) % mod;ll ans = 0;ll k ;for(int i = 0;i <= n;++i) {k=1;if(i & 1) k = -1;ans += k * C(n,i) * A(n,i) % mod * F[n - i] % mod * F[n - i] % mod;ans %= mod;}printf("%lld\n",(ans + mod) % mod);return 0; }總結(jié)
以上是生活随笔為你收集整理的牛客网 【每日一题】4月10日 二分图染色(弱化版)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C#方法讲解——飞行棋画地图
- 下一篇: 魅族16th系统更新服务器异常,魅族16