Burnside引理&Polya定理-置换群-学习笔记

i207M

2019-01-04 07:25:13

Personal

[远古时期写的博客](https://www.luogu.org/blog/i207M/burnside-yin-li-polya-ding-li-xue-xi-bi-ji) 主要是毕克的讲课内容 ### Lucas数 长度为n的环,选一些点,两两不相邻的方案数。$L[0]=2,L[1]=1,L[n]=L[n-1]+L[n-2]$ #### HDU 5868,POJ 2888 矩阵乘法 #### BZOJ 1004 DP ### [SHOI2006]有色图 ```cpp int md; il int qpow(int a,int b) { int res=1; for(; b; b>>=1,a=(LL)a*a%md) if(b&1) res=(LL)res*a%md; return res; } int n,m; int tot; int num[100],cnt[100],tp; il int gcd(int a,int b) { ri t; while(b) t=a,a=b,b=t%b; return a; } int fac[100],inv[100],ifac[100]; void prework() { fac[0]=ifac[0]=fac[1]=ifac[1]=inv[1]=1; for(ri i=2; i<=60; ++i) fac[i]=(LL)fac[i-1]*i%md,inv[i]=(LL)(md-md/i)*inv[md%i]%md; for(ri i=2; i<=60; ++i) ifac[i]=(LL)ifac[i-1]*inv[i]%md; } int calc() { int ans=0; for(ri i=1; i<=tp; ++i) ans=(ans+(LL)num[i]/2*cnt[i])%md; for(ri i=1; i<=tp; ++i) { for(ri j=i+1; j<=tp; ++j) { ans=(ans+(LL)cnt[i]*cnt[j]*gcd(num[i],num[j]))%md; } ans=(ans+(LL)cnt[i]*(cnt[i]-1)/2*num[i])%md; } ans=qpow(m,ans); int ci=fac[n]; for(ri i=1; i<=tp; ++i) ci=(LL)ci*qpow(inv[num[i]],cnt[i])%md*ifac[cnt[i]]%md; tot=(tot+ci)%md; return (LL)ans*ci%md; } int ans; void dfs(int r) { if(!r) { ans=(ans+calc())%md; return; } for(ri v=num[tp]-1; v>=2; --v) { int x=r-v,t=++tp; num[t]=v,cnt[t]=1; for(; x>=0; x-=v,++cnt[t]) dfs(x); --tp; } num[++tp]=1,cnt[tp]=r; dfs(0); --tp; } int solve() { num[0]=n+1; dfs(n); return (LL)ans*qpow(tot,md-2)%md; } signed main() { #ifdef M207 freopen("in.in","r",stdin); // freopen("out.out","w",stdout); #endif in(n,m,md); prework(); out(solve()); return 0; } ``` ### Codechef ADIMAT 如果一个矩阵能通过首先任意改变行的顺序,再任意改变列的顺序,从而变成另一个矩阵,那么这两个矩阵相同,而相同的矩阵只应当被计算一次。 由于答案可能很大,请输出答案对10^9 + 7 取模的结果。 先枚举两维中较小的一维(<23),然后枚举它的整数划分(就是轮换),然后对于另一维的划分,使用DP求出总方案。 这里我用的方法和毕克上课说的不太一样,没有使用去重的完全背包,而是直接计算: $dp[i]$表示已经处理了i个位置的贡献。每次枚举最后一个位置和几个数组成一组$C^{j-1}_{i-1}$,这一组内的情况(圆排列$(j-1)!$),两部分的贡献$g[j]\times dp[i-j]$ 其中,$g[i]$的计算方法是:和行的每一个轮换形成了若干个矩形,每个矩形内的轨道数为$gcd(i,j)$ ```cpp int calc() { for(ri i=1; i<=m; ++i) { int val=1; for(ri j=1; j<=tp; ++j) val=(LL)val*qpow(2,gcd(i,num[j])*cnt[j])%md; g[i]=val; } for(ri i=1; i<=m; ++i) { int tot=0; for(ri j=1; j<=i; ++j) tot=(tot+(LL)c[i-1][j-1]*fac[j-1]%md*g[j]%md*dp[i-j]%md)%md; dp[i]=tot; } int ci=fac[n]; for(ri i=1; i<=tp; ++i) ci=(LL)ci*ifac[cnt[i]]%md*qpow(inv[num[i]],cnt[i])%md; return (LL)dp[m]*ci%md; } ``` *以下为毕克在WC时的讲课内容* ### Problem1 Path 在一个 n×n 的网格中,从左下角到右上角,每次向上或者向右 走一格,一共需要向右走 n 次,向上走 n 次。输入 n(1 ≤ n ≤ 10^6),问本质不同的方案有多少种。结果对 p = 10^9 + 9 取模。 如果两个方案可以通过对称和旋转变成相同的,我们认为他们本质相同。 将路径变为01串,第一个操作是01取反,第二个操作是将字符串翻转 分类讨论4种情况即可。 不动:$2n\choose n$ 翻转:${n \choose n/2}[n\mod 2=0]$ 取反:0 翻转且取反:$2^n$ ### Problem 6 Wool 吕欣寒假讲的。