二分图染色(弱化版)题解

乍看一下,此题貌似很简单,仔细一想,竟然完全不可做。。。

然后,开始思考怎么搞这道题。。。

首先,我们因为每个边都要染色,所以,我们不妨先给所有边都染上最没影响的颜色——绿色

然后,我们只需考虑,将绿色的边改成红色或者蓝色即可~

我们来推导一下

如果既有蓝色,又有红色,尝试推导一下,发现情况太多,而且难以递推

那么,我们先从简单入手

假设,现在我们只有红色或者只有蓝色(以下假设连红边),此时答案是多少呢?

考虑递推

\(fi\)表示有i对点的完全二分图,然后,我们只有红色以及绿色涂料的时候,方案数是多少

可以轻松手算出来,\(f0=1,f1=2\)

然后,假设我们算出了所有\(f1->f(i-1)\),这时怎么算\(fi\),我们画个图,发现,我们现在就相当于在i-1的图下面加了一对点,那么,我们分类讨论这对点的连边情况

1.这对点只连绿边

方案数为\(f(i-1)\)

2.这对点之间连了一条红边

发现这对点现在只能连绿边了,所以方案数为\(f(i-1)\)

3.这对点之间连绿边,且至少一个点连了红边

我们来想下,这对边中的一个点,与之前的一个点之前连了一条红边,那么,其实就相当于还剩i-1对待连边的点(刚刚连边的点已经无法连其他红边了),而两个点分别对应的点仍然可以连边,所以方案数就是:

\(2*(i-1)[两个点选一个,i-1对点选一对]*f(i-1)\)

但是我们发现,对于左边和右边都连了红边的情况,我们计算了两次,所以我们还有减去两边都连了红边(不相连)的情况,即减去

\((i-1)^2[各选(i-1)对点]*f(i-2)\)

所以,\(fi=2*i*f(i-1)-(i-1)^2*f(i-2)\)

然后,我们再考虑有蓝边的情况

我们发现直接用容斥就可以算出答案了

即:\(ans=\sum_{k=0}^{n}\)\((−1)^{k}\)\((C_{n}^{k})^2\)\(i!\)\(f(n−k)^2\)

我们直接递推组合数,再预处理出\(f\)数组就可以直接算了!

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e7+1,mod=1e9+7;
int f[N],s[N],g[N];
int main(){
    int n;
    scanf("%d",&n);
    f[0]=1,f[1]=2;
    for(int i=2;i<=n;++i){
        f[i]=(((2LL*i*f[i-1])%mod)-(1LL*((1LL*(i-1)*(i-1))%mod)*f[i-2]))%mod;
    }
    for(int i=1;i<=n;++i){
        f[i]=(1LL*f[i]*f[i])%mod;
    }
    s[0]=s[1]=1;
    for(int i=2;i<=n;++i){
        s[i]=(1LL*s[i-1]*i)%mod;
    }
    g[0]=g[1]=1;
    int ans=0,C=n;bool now=0;
	for(int i=2;i<=n;++i){
        now^=1;g[i]=(1LL*g[mod%i]*(mod-mod/i))%mod;
        C=(1LL*C*(n-i+1))%mod,C=(1LL*C*g[i])%mod;
        int fow=(1LL*((1LL*((1LL*C*C)%mod)*s[i])%mod)*f[n-i])%mod;
        if(now){
            ans=(ans+fow)%mod;
        }else{
            ans=(ans-fow)%mod;
        }
    }
    ans=(ans+f[n])%mod;
    ans=(ans-(1LL*((1LL*n*n)%mod)*f[n-1]))%mod;
    ans=(ans+mod)%mod;
    printf("%d",ans);
    return 0;
}
posted @ 2020-04-10 15:23  ThinkofBlank  阅读(190)  评论(0编辑  收藏  举报