恢复训练(学不动了摸会鱼) Pt. 1
本来下午想把pre稿子写了,咕咕咕。
群论是啥也不会了,写个polya试试(手动doge)为什么博客媛没有emoji,以后万一自己搭博客一定要加上这个小东西
polya淼题:poj1286
先复吸一下polya
本来有这么个burnside引理,为什么叫引理呢,因为polya的证明引用了这个小可爱。
正经人谁好好写公式,(其实是不会群论的正规表达方式)
比如说从前有这么个置换群$F = \{ f_i , i \in Z and 1\le i \le n_F \} $ 其中 $n_F = \| F \|$ 集合元素总数。$f_i$表示一种置换(一个n的全排列)。
注意应用有限次任意$f_i$的迭代并不会得到不属于$F$的置换
我们要给一个长为n的序列染色。若我们想得到在置换群$F$下本质不同的染色结果(染色结果A与B本质相同,当且仅当对A有限次应用$F$中的任意置换后可以得到B)
那么$Burnside$引理告诉我们这种染色数是
$\frac{1}{\| F \|}\sum_{i}^{n_F}{Count(f_i)}$
其中$Count(\cdot)$表示在应用一次某种置换后颜色序列不变的染色种类数,即在$f_i$置换下恒不变的颜色序列(不动点状态)
具体的例子可以看看百度百科的那个方块染色,我觉得不错。
Polya定理是burnside的具体化,也就是说只在某种情况下burnside的应用。
这种情况就是序列每个位置都可以染任意m种颜色中的一个。
此时$Count(\cdot)$可以被重写。
若一个置换群$f_i$是由$k_i$个子置换组成的,一个子置换中元素永远也无法到达另一个子置换中的位置。
此时$Count(f_i) = m^{k_i}$
$P\acute{o}lya 定理: \frac{\sum{m^{k_i}}}{\| F \|}$
好了长度水差不多了,简单说一下解题思路哈
显然可以用Polya 做嘛 (doge)
置换就暴力拿出来一个一个看。一共2n个置换,n个转动项链的置换 {2,3,4, ... ,n, 1}, {3, 4, 5, ..., n, 1, 2}, ..., {n, 1, 2, ..., n-1}
还有n个在项链背面转的: {n, n-1, ... , 3, 2, 1}, {n-1, n-2, ..., 2, 1, n}, ...
记一下数就好了
后来发现好像不用把子置换记一遍数,奇数环1个子置换,偶数环有时有两个子置换,反环置换数也可以统计
不管了反正A了
Code:
#include<cstdio> #include<cstring> #include<algorithm> typedef long long lnt; int a[100]; int vis[50]; lnt sPow(lnt aa, int b){ lnt ans = 1; while(b){ if(b % 2) ans *= aa; aa *= aa; b /= 2; } return ans; } void dfs(int now){ if(vis[now]) return ; vis[now] = 1; dfs(a[now]); return ; } lnt count(int n){ int ans = 0; memset(vis, 0, sizeof(vis)); for(int i=1; i<=n; ++i) if(! vis[i]){ ++ans; dfs(i); } return sPow(3ll, ans); } lnt polya(int n){ if(!n){ return 0; } lnt sum = 0; for(int delta=0; delta<n; ++delta){ for(int i=0; i<n; ++i){ a[(i+delta)%n + 1] = i+1; } sum += count(n); for(int i=0; i<n/2; ++i) std::swap(a[i+1], a[n-i]); sum += count(n); } return sum / (2ll*n); } int main(){ int n; while(true){ scanf("%d", &n); if(n == -1) return 0; printf("%lld\n", polya(n)); } return 0; }
再弄点计算几何(doge)
随处找找
发现lgl巨佬这里有不少题诶
(我好像一个也不会诶...)%%% lgl
算了先打开一个看看
先来这个poj3525
17.00 了,还不会。·咕咕咕
肝pre去了(doge)