HDU 2865 Birthday Toy polya 矩阵快速幂 欧拉函数
来源:互联网 发布:windows解压mac压缩包 编辑:程序博客网 时间:2024/05/24 00:15
分析:题意略过。就是求相邻颜色不同的置换数目。还是老思路,求不动点然后取平均数。下面讲如何求不动点。
假设我们知道了一个置换的循环数目。如何求相邻颜色不同的不动点数目。我们把环从正上方切开,然后取正上方的那个珠子加到尾部。这个问题的本质是一样的。
因为有k种颜色,内圈的珠子取一个,外圈只能取剩下的k-1中,下面我们就认为k = k-1,不考虑内圈。
从左往右推,我们假设第i个珠子的取第j种颜色的方案数为c(i,j),那么有这样的公式 c(i,j) = ∑c(i-1,p)( (p = 1,2,...k, p != j);根据这个我们可以推出一个矩阵
0 1 1 1
1 0 1 0
1 1 0 0
右边那列是第一个珠子的取值情况,然后每次左乘一个矩阵,就变成下一个珠子的取值情况,而方案数,就是最后一个珠子的取值的总和。但是这样分析后我们发现这样是不够的,因为矩阵的幂 = 循环数 最大为n, 矩阵的长 = K 颜色数,而这两者取值都可以到1e9。如果这样解的话,时间复杂度为O(n^3*log k);我们给行列一些标号然后再研究他们的规律且看
设矩阵长为 n
0 1 1 xi xi+1 = yi * (n-1)
1 0 1 * yi = yi+1 = xi + yi *(n-2)
1 1 0 yi yi+1 = xi + yi *(n-2)
所以,与其计算之前那个矩阵的n-1次幂然后再乘以右边那一列,不如直接计算xi yi;回到之前, 当我们计算矩阵的n-1次幂然后乘以那一列后,除了第一行的数,其他的加起来就是结果。换言之,y(n-1)*(n-1) 正好等于xn,我们计算新的矩阵
0 n-1
1 n -2
的n次幂直接取第一行第一列的数即可。
解决了这个问题,我们继续看,如果用常规枚举GCD的方法,需要O(n)的时间复杂度,也是无法承受,所以我们要利用欧拉函数来求1-n的所有GCD,详见代码。
#include<cstdio>typedef long long LL;const int SIZE = 2;const int MOD = 1000000007;const int N = 40009;const int M = 1000008;LL prime[N];int phi[M];bool vi[N];int p;//数论相关void get_prim_and_eular(){ p = 0; for(int i = 2; i < N; i++){ if(!vi[i]){ prime[p++] = i; for(int j = i * i; j < N; j += i) vi[j] = true; } } phi[1] = 1; for(int i = 2; i < M; i++) if(!phi[i]){ for(int j = i; j < M; j += i){ if(!phi[j]) phi[j] = j; phi[j] = phi[j]/ i * (i-1); } }}int eular(int n){ if(n < M) return phi[n]; int ans = n; for(int i = 0; i < p && prime[i] * prime[i] <= n; i++) if(n % prime[i] == 0){ ans = ans / prime[i] * (prime[i]-1); while(n % prime[i] == 0) n /= prime[i]; } if(n > 1) ans = ans / n * (n-1); return ans;}LL pow_mod(LL base, int exp){ LL ret = 1; while(exp){ if(exp&1) ret = ret * base % MOD; base = base * base % MOD; exp >>= 1; } return ret;}LL inver(int t){ return pow_mod(t, MOD-2);}//快速幂相关struct Mat{ LL m[SIZE][SIZE]; Mat(){m[0][0] = m[0][1] = m[1][0] = m[1][1] = 0;}};Mat mul(const Mat &A,const Mat &B){ Mat C; for(int i = 0; i < SIZE; i++){ for(int j = 0; j < SIZE;j++){ for(int k = 0; k < SIZE; k++) C.m[i][j] = (C.m[i][j] + A.m[i][k] * B.m[k][j]) % MOD; } } return C;}Mat pow(Mat A, LL n){ Mat B; for(int i = 0; i < SIZE; i++) B.m[i][i] = 1; while(n){ if(n&1) B = mul(B, A); A = mul(A, A); n >>= 1; } return B;}//计算polyaLL cal(int d, int c){ Mat a; a.m[0][1] = c - 1; a.m[1][0] = 1; a.m[1][1] = c - 2; return c * pow(a, d).m[0][0] % MOD;}int main(){ get_prim_and_eular(); int n,k; while(scanf("%d%d", &n, &k) == 2){ LL ans = 0; int t = n; for(int i = 1; i * i<= n; i++)if(n % i == 0){ ans = (ans + cal(i, k-1) * eular(n/i) % MOD) % MOD; if(i * i != n) ans = (ans + cal(n/i, k-1) * eular(i) % MOD) % MOD; } ans = ans * inver(n) % MOD; ans = ans * k % MOD; printf("%I64d\n", ans); }}
- HDU 2865 Birthday Toy polya 矩阵快速幂 欧拉函数
- HDU 2865 Birthday Toy(Polya+矩阵乘法+dp)
- hdu 2865 Birthday Toy (polya,好题)
- HDU 2865 Birthday Toy(Polya综合)
- hdu-5868 Different Circle Permutation 矩阵快速幂 + 欧拉函数 + polya计数定理
- HDU 5868 Different Circle Permutation(dp+polya+矩阵快速幂+欧拉函数)
- HDU 5868 ACM/ICPC Regional Dalian Online(polya计数+矩阵快速幂+欧拉函数)
- hdu 2865 Birthday Toy 及我对polya的总结
- HDU Birthday Toy 特殊限制的polya
- POJ 2888 Magic Bracelet(Polya计数+dp+矩阵快速幂+欧拉函数+乘法逆元)
- hdu 2865 Birthday Toy (置换+DP+矩阵乘法)
- POJ2154 Color【Polya定理】【欧拉函数】【整数快速幂】
- HDU 5667 Sequence【矩阵快速幂】【欧拉函数】
- hdu 5667(矩阵快速幂+欧拉函数)
- HDU 5895 矩阵快速幂+欧拉函数
- POJ 2888 Magic Bracelet (Polya+欧拉函数+矩阵乘法)
- HDU 2865 Birthday Toy(ploya好题)
- 欧拉函数+矩阵快速幂 Password
- TCP协议可靠性数据传输实现原理分析
- PF_RING Libzero中使用HugePage
- 【Leetcode】Search for a Range
- VC++实现Vista和Win7系统低权限程序向高权限程序发消息
- Merge k Sorted Lists
- HDU 2865 Birthday Toy polya 矩阵快速幂 欧拉函数
- leetcode - Multiply Strings
- win7安装odoo8错误
- topcoder SRM 637 DIV2题解
- Codeforces Round #264 (Div. 2) E. Caisa and Tree 树上操作暴力
- IOS学习---OC基础学习(ARC 协议)
- linux上搭建svn服务器
- Linux Makefile学习
- gclient sync 出错处理