乍看一下,此题貌似很简单,仔细一想,竟然完全不可做。。。
然后,开始思考怎么搞这道题。。。
首先,我们因为每个边都要染色,所以,我们不妨先给所有边都染上最没影响的颜色——绿色
然后,我们只需考虑,将绿色的边改成红色或者蓝色即可~
我们来推导一下
如果既有蓝色,又有红色,尝试推导一下,发现情况太多,而且难以递推
那么,我们先从简单入手
假设,现在我们只有红色或者只有蓝色(以下假设连红边),此时答案是多少呢?
考虑递推
设表示有i对点的完全二分图,然后,我们只有红色以及绿色涂料的时候,方案数是多少
可以轻松手算出来,
然后,假设我们算出了所有,这时怎么算,我们画个图,发现,我们现在就相当于在i-1的图下面加了一对点,那么,我们分类讨论这对点的连边情况
1.这对点只连绿边
方案数为
2.这对点之间连了一条红边
发现这对点现在只能连绿边了,所以方案数为
3.这对点之间连绿边,且至少一个点连了红边
我们来想下,这对边中的一个点,与之前的一个点之前连了一条红边,那么,其实就相当于还剩i-1对待连边的点(刚刚连边的点已经无法连其他红边了),而两个点分别对应的点仍然可以连边,所以方案数就是:
但是我们发现,对于左边和右边都连了红边的情况,我们计算了两次,所以我们还有减去两边都连了红边(不相连)的情况,即减去
所以,
然后,我们再考虑有蓝边的情况
我们发现直接用容斥就可以算出答案了
即:
我们直接递推组合数,再预处理出数组就可以直接算了!
代码
#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; }