bzoj 4330: JSOI2012 爱之项链
听说这题不公开.. 那就不贴题意了
首先要用burnside引理求出戒指的种数,那么对于一个顺时针旋转$k$个位置的置换就相当于连上一条$(i,(i+k)%R)$的边,每个环颜色必须相同
环的个数为$gcd(k,R)$,所以这样的方案数就有$R^{gcd(k,R)}$种
然后dp求项链的方案数,设$g_{i,0}$表示$1$和$i$不同,中间相邻不同的方案数,$g_{i,1}$表示$1$和$i$相同,中间相邻不同的方案数
那么有如下推导:
$$g_{i,0}=(i-1)g_{i-1,1}+(i-2)g_{i-1,0}$$
$$g_{i,1}=g_{i-1,0}$$
再化一下:$$g_{i,0}=(i-1)g_{i-2,0}+(i-2)g_{i-1,0}$$
由于我们需要的也就是$g_{i,0}$,不妨设$f_i=g_{i,0}$,所以:$$f_i=(i-1)f_{i-2}+(i-2)f_{i-1}$$
这就可以用矩阵乘法优化 听说有通项公式
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <algorithm> 5 #include <cmath> 6 #define LL long long 7 using namespace std; 8 const LL Mod = 3214567; 9 const LL Maxn = 1000010; 10 LL n, m, r; 11 LL gcd ( LL a, LL b ){ 12 if ( a == 0 ) return b; 13 return gcd ( b%a, a ); 14 } 15 LL pow ( LL x, LL k ){ 16 LL ret = 1; 17 while (k){ 18 if ( k & 1 ) ret = (ret*x)%Mod; 19 x = (x*x)%Mod; 20 k >>= 1; 21 } 22 return ret; 23 } 24 struct matrix { 25 LL a[2][2]; 26 LL l1, l2; 27 void clear (){ memset ( a, 0, sizeof (a) ); } 28 }trans, x, z, fi; 29 matrix ttimes ( matrix x, matrix y ){ 30 matrix ret; 31 ret.clear (); 32 ret.l1 = x.l1; ret.l2 = y.l2; 33 LL i, j, k; 34 for ( i = 0; i < ret.l1; i ++ ){ 35 for ( j = 0; j < ret.l2; j ++ ){ 36 for ( k = 0; k < x.l2; k ++ ){ 37 ret.a[i][j] = ( ret.a[i][j] + (x.a[i][k]*y.a[k][j])%Mod ) % Mod; 38 } 39 } 40 } 41 return ret; 42 } 43 LL phi ( LL x ){ 44 LL ret = x, sq = sqrt (x); 45 for ( LL i = 2; i <= sq; i ++ ){ 46 if ( x % i == 0 ){ 47 ret = ret/i*(i-1); 48 while ( x % i == 0 ) x /= i; 49 } 50 } 51 if ( x > 1 ) ret = ret/x*(x-1); 52 return ret; 53 } 54 int main (){ 55 LL i, j, k; 56 scanf ( "%lld%lld%lld", &n, &m, &r ); 57 LL o = 0, sq = sqrt (m); 58 for ( i = 1; i <= sq; i ++ ){ 59 if ( m % i == 0 ){ 60 o = (o+(pow(r,i)*phi(m/i))%Mod)%Mod; 61 if ( i*i == m ) continue; 62 o = (o+(pow(r,m/i)*phi(i))%Mod)%Mod; 63 } 64 } 65 LL inv = pow ( m, Mod-2 ); 66 o = (o*inv)%Mod; 67 if ( n == 1 ){ printf ( "0\n" ); return 0; } 68 trans.l1 = trans.l2 = 2; 69 trans.a[0][1] = o-1; trans.a[1][0] = 1; trans.a[1][1] = o-2; 70 x = trans; 71 z.l1 = z.l2 = 2; 72 z.a[0][0] = 1; z.a[1][1] = 1; 73 for ( i = n-2; i >= 1; i >>= 1 ){ 74 if ( i & 1 ) z = ttimes ( z, x ); 75 x = ttimes ( x, x ); 76 } 77 fi.l1 = 1; fi.l2 = 2; 78 fi.a[0][1] = (o*(o-1))%Mod; 79 fi = ttimes ( fi, z ); 80 printf ( "%lld\n", fi.a[0][1] ); 81 return 0; 82 }
作者:Ra1nbow
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。