本小结会不断更新,转载请注明出处:http://blog.csdn.net/xdu_truth/article/details/8033524
(1)循环:
在一个置换下 如果x1->x2,x2->x3,...,xn->x1;
x1,x2,x3,...,xn就形成了一个循环。
(2)ploya定理:
定义ck为在置换ak下的循环总数
设G = {a1,a2,a3,...,a|G|}是N ={1,2,3,...,N}上的置换群,现用m种颜色对着N个点染色,则不同的染色方案数为:
S = (m^c1 + m^c2 + ... + m^c|G|)/|G|
(3)常见置换的循环数:
旋转: n个点顺时针(或逆时针)旋转i个位置的置换,循环数为gcd(n,i)
翻转:
n为偶数时: 对称轴不过顶点:循环数为n/2;
对称轴过顶点:循环数为n/2+1;
n为奇数时:循环数为(n+1)/2;
pku2409 Let it Bead (公式题)
code:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> using namespace std; int gcd(int a,int b) { return b==0 ? a:gcd(b,a%b); } int _pow(int p,int n) { int ret = 1; while(n) { if(n&1)ret *= p; p *= p; n /= 2; } return ret; } int main() { int n,m; while(~scanf("%d%d",&m,&n),n|m) { int ans = 0; for(int i=1;i<=n;i++) ans += _pow(m,gcd(n,i)); if(n&1) ans += n*_pow(m,(n+1)/2); else ans += (n/2)*_pow(m,n/2)+(n/2)*_pow(m,n/2+1); ans /= (2*n); printf("%d\n",ans); } return 0; }
pku2154 Color
题意:给出两个整数n和p,代表n个珠子,n种颜色,要求不同的项链数(旋转重合算同一种,翻转重合不算同一种),并对结果mod(p)处理。
不错的一个数学题,
根据ploya定理,结果为:(1/n * ∑n^gcd(n,i)) % p (i=1,..,n)
但是n<=1000000000,显然这个公式需要化简一下。
gcd(n,i)的所有取值是n的所有约数,所以对于某个约数x,我们考虑n^x系数:
由于gcd(n,i) = x ,
那么gcd(n/x,i/x) = 1,
所以系数即为所有满足上式的i的个数,即欧拉函数 euler(n/x);
这样公式就化简为了: (1/n * ∑Euler(n/x)(n^x)) % p (x为n的所有约数)
code:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> using namespace std; int n,mod; int powmod(int p,int m) { int ret = 1; while(m) { if(m&1)ret=(ret * p)%mod; p = (p*p)%mod; m >>= 1; } return ret; } int euler(int x) { int res = x; for(int i=2;i<(int)sqrt(x*1.0)+1;i++) { if(x%i == 0) { res = res/i*(i-1); while(x%i==0) x/=i; } } if(x>1)res = res/x*(x-1); return res%mod; } int main() { //freopen("input.txt","r",stdin); int cases; scanf("%d",&cases); while(cases-- && scanf("%d%d",&n,&mod)) { int ans = 0; for(int x=1;x*x<=n;x++) { if(n%x==0) { ans = (ans+euler(n/x)*powmod(n%mod,x-1))%mod; if(n/x != x)ans = (ans+euler(x)*powmod(n%mod,n/x-1))%mod; } } printf("%d\n",ans); } return 0; }