HDU4291 A Short problem

求通项和斐波那契数列的方法一样,矩阵快速幂。

这道题麻烦在套了三层。

但其实取模这种操作肯定会出现循环的,可以先本地暴出循环节,1000000007对应的循环节是222222224,222222224对应的循环节是183120。

最外层的结果是对1000000007取模,它的内层对222222224取模,可以得到相等的答案,那么222222224的内层对183120取模,也能得到相等的答案,这样就是分别对三个模数做矩阵快速幂,内层得到的结果返回给外层作为指数。

 1 #include<stdio.h>

 2 #include<stdlib.h>

 3 #include<string.h>

 4 typedef __int64 LL;

 5 struct Matrix

 6 {

 7     LL Mt[2][2];

 8     void init0(){memset(Mt, 0, sizeof(Mt));}

 9     void init1() {init0(), Mt[0][0] = Mt[1][1] = 1;}

10     Matrix(){init0();}

11     Matrix(LL num) {init0();Mt[0][0] = Mt[1][1] = num;}

12     Matrix(LL a, LL b, LL c, LL d){Mt[0][0] = a, Mt[0][1] = b, Mt[1][0] = c, Mt[1][1] = d;}

13     Matrix Mul(const Matrix &b, LL mod)

14     {

15         int i, j, k;Matrix res;

16         for(i = 0; i < 2; ++ i)

17             for(j = 0; j < 2; ++ j)

18                 for(k = 0; k < 2; ++ k)

19                     res.Mt[i][j] = (res.Mt[i][j] + Mt[i][k] * b.Mt[k][j]) % mod;

20         return res;

21     }

22     Matrix Rep(LL p, LL mod)

23     {

24         Matrix b = *this, res(1);

25         if(p == 0) return res;

26         if(p == 1) return b;

27         while(p > 1)

28         {

29             if(p & 1) res = res.Mul(b, mod);

30             b = b.Mul(b, mod);

31             p >>= 1;

32         }

33         return b.Mul(res, mod);

34     }

35 };

36 LL Cal(LL n, LL mod)

37 {

38     Matrix mm(3, 1, 1, 0), ori(1, 0, 0, 0);

39     if(!n) return 0;

40     return ori.Mul(mm.Rep(n - 1, mod), mod).Mt[0][0];

41 }

42 int main()

43 {

44     LL n;

45     while(scanf("%I64d", &n) != EOF)

46         printf("%I64d\n", Cal(Cal(Cal(n, 183120), 222222224), 1000000007));

47     return 0;

48 }

你可能感兴趣的:(HDU)