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 }
View Code
posted @ 2016-11-02 11:29  Ra1nbow  阅读(199)  评论(1编辑  收藏  举报