1.西瓜恒等式:
$$\sum_{P.is.a.permutation}{\frac{1}{A[P[1]]×(A[P[1]]+A[P[2]])×...×(A[P[1]]+...+A[P[n]])}}=\frac{1}{A[1]×A[2]×...×A[n]}$$
2.西瓜定理:
对于任意am+4≡a(mod m),有:
3.给一个无向图,你需要给边染色(k种颜色),在允许将一个简单环经行旋转的情况下,问本质不同的图的数量。
答案显然对于每一个点双连通分量是独立的,对于每一个点双连通分量,我们把它们的贡献乘起来,而不在点双上的一条边,有 k 种染色方法,所有贡献乘起来即可。
对于树的情况,每个点双连通分量只有一个点,答案显然为 km。
对于环的情况,若一个点双连通分量只有一个点,则没有贡献,其他情况一个点双连通分量就是一个环,对于一个环只有循环左移操作,用 polya 定理求答案即可。
剩下的情况一个点双中至少存在两个有相交部分的环,我们考虑先分别把两个小环顺时针操作,再把两个小环所在的大环逆时针操作,这样三步之后其余位置都不变,只有相邻两个交换了位置,因为我们可以交换特定位置上的两个且可以循环左移,我们就可以任意排列这些元素,即在一个至少有两个环的点双上,两个方案只要每种颜色出现次数相同,我们就能把它们变得一样。方案数为C(m+k-1,k-1)。(画图理解)
把以上三种贡献乘起来即可。
1 #include<bits/stdc++.h> 2 #define pb push_back 3 4 using namespace std; 5 6 const int N=55,M=205,P=1e9+7; 7 typedef long long ll; 8 9 vector<int>e[N]; 10 int dfn[N],low[N],dfc,st[N],tp,fac[M],ifac[M]; 11 int n,m,k,ans=1; 12 set<int>dat; 13 14 int fpow(int a,int t){static int r;for(r=1;t;t>>=1,a=(ll)a*a%P)if(t&1)r=(ll)r*a%P;return r;} 15 int C(int n,int m){return (ll)fac[n]*ifac[m]%P*ifac[n-m]%P;} 16 int gcd(int x,int y){return y?gcd(y,x%y):x;} 17 int polya(int n){int r=0;for(int i=1;i<=n;i++)r=(r+fpow(k,gcd(n,i)))%P;return (ll)r*fpow(n,P-2)%P;} 18 int permu(int m){return C(m+k-1,k-1);} 19 20 void tarjan(int x,int fa){ 21 dfn[x]=low[x]=++dfc,st[++tp]=x; 22 for(int v:e[x])if(v!=fa){ 23 if(!dfn[v]){ 24 tarjan(v,x),low[x]=min(low[x],low[v]); 25 if(low[v]>=dfn[x]){ 26 dat.clear(); 27 int n=0,m=0,las; 28 do dat.insert(st[tp]),las=st[tp],st[tp--]=0,n++;while(las!=v); 29 dat.insert(x),n++; 30 for(int u:dat)for(int v:e[u])if(dat.count(v))m++;m>>=1; 31 if(m<n)ans=(ll)ans*k%P; 32 else if(m==n)ans=(ll)ans*polya(n)%P; 33 else ans=(ll)ans*permu(m)%P; 34 } 35 }else low[x]=min(low[x],dfn[v]); 36 } 37 if(fa==0)st[tp--]=0; 38 } 39 40 int main(){ 41 freopen("graph.in","r",stdin); 42 freopen("graph.out","w",stdout); 43 scanf("%d%d%d",&n,&m,&k); 44 fac[0]=1; 45 for(int i=1;i<=m+k;i++)fac[i]=(ll)fac[i-1]*i%P; 46 ifac[m+k]=fpow(fac[m+k],P-2); 47 for(int i=m+k;i>=1;i--)ifac[i-1]=(ll)ifac[i]*i%P; 48 for(int i=1,u,v;i<=m;i++)scanf("%d%d",&u,&v),e[u].pb(v),e[v].pb(u); 49 for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i,0); 50 printf("%d\n",ans); 51 return 0; 52 }