[校内训练20_01_21]ABC

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
",ans);
51     return 0;
52 }
View Code
原文地址:https://www.cnblogs.com/GreenDuck/p/12252863.html