HDU4565 So Easy! —— 共轭构造、二阶递推数列、矩阵快速幂

题目链接:https://vjudge.net/problem/HDU-4565

So Easy!

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5525    Accepted Submission(s): 1841


Problem Description
  A sequence Sn is defined as:

Where a, b, n, m are positive integers.┌x┐is the ceil of x. For example, ┌3.14┐=4. You are to calculate Sn.
  You, a top coder, say: So easy! 
Input
  There are several test cases, each test case in one line contains four positive integers: a, b, n, m. Where 0< a, m < 215, (a-1)2< b < a2, 0 < b, n < 231.The input will finish with the end of file.
 
Output
  For each the case, output an integer Sn.
 
Sample Input
2 3 1 2013 2 3 2 2013 2 2 1 2013
 
Sample Output
4 14 4
 
Source
 
Recommend
zhoujiaqi2010

题解:

1.因为:0< a,(a-1)2< b < a2,。当a>=1时, a-1<根号b<a,那么 0<(a-根号b)<1;当0<a<1时, 1-a<根号b<a,那么 那么 0<(a-根号b)<2*a-1<1。综上:0<(a-根号b)<1。所以0<(a-根号b)^n<1

2.这里假设b = 根号b,以方便描述。根据上述结论,那么可得:[(a+b)^n] = [(a+b)^n + (a-b)^n] = (a+b)^n + (a-b)^n 。

解释:

2.1 因为a-1<b<1,所以b必定是浮点数,那么(a+b)^n 也必定是浮点数,此时,再加上个大于0小于1的浮点数(a-b)^n,那么 [(a+b)^n + (a-b)^n] 有可能等于[(a+b)^n] ,也有可能等于[(a+b)^n] +1,这就要取决(a+b)^n的小数部分与(a-b)^n的小数部分之和是否大于1。

2.2 此时,就要将(a+b)^n+(a-b)^n展开进行分析。展开后可知,当b的指数为奇数时,正负抵消;当b的指数为偶数时,b^2k 为一个整数。综上:(a+b)^n+(a-b)^n为一个整数,即表明(a+b)^n的小数部分与(a-b)^n的小数部分之和刚好等于1,所以[(a+b)^n] = [(a+b)^n + (a-b)^n] = (a+b)^n + (a-b)^n 。

3.根据上述分析,问题转化为求:S[n] = (a+b)^n + (a-b)^n 。而这个式子可以看成是二阶齐次递推式的通项公式,可以根据通项公式反推回递推式,然后构造矩阵进行求解。具体如下:

以上来自:http://blog.csdn.net/ljd4305/article/details/8987823

代码如下:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <cmath>
 7 #include <queue>
 8 #include <stack>
 9 #include <map>
10 #include <string>
11 #include <set>
12 using namespace std;
13 typedef long long LL;
14 const int INF = 2e9;
15 const LL LNF = 9e18;
16 //const int MOD = 1e9+7;
17 const int MAXN = 1e6+100;
18 
19 int MOD;
20 const int Size = 2;
21 struct MA
22 {
23     LL mat[Size][Size];
24     void init()
25     {
26         for(int i = 0; i<Size; i++)
27         for(int j = 0; j<Size; j++)
28             mat[i][j] = (i==j);
29     }
30 };
31 
32 MA mul(MA x, MA y)
33 {
34     MA ret;
35     memset(ret.mat, 0, sizeof(ret.mat));
36     for(int i = 0; i<Size; i++)
37     for(int j = 0; j<Size; j++)
38     for(int k = 0; k<Size; k++)
39         ret.mat[i][j] += 1LL*x.mat[i][k]*y.mat[k][j]%MOD, ret.mat[i][j] = (ret.mat[i][j]%MOD+MOD)%MOD;
40     return ret;
41 }
42 
43 MA qpow(MA x, LL y)
44 {
45     MA s;
46     s.init();
47     while(y)
48     {
49         if(y&1) s = mul(s, x);
50         x = mul(x, x);
51         y >>= 1;
52     }
53     return s;
54 }
55 
56 
57 int main()
58 {
59     LL a, b, n, m, f[2];
60     while(scanf("%lld%lld%lld%lld", &a,&b,&n,&m)!=EOF)
61     {
62         MOD = (int)m;
63         f[0] = 2; f[1] = 2*a;
64         if(n<=1)
65         {
66             printf("%lld
", f[n]%MOD);
67             continue;
68         }
69 
70         MA s;
71         memset(s.mat, 0, sizeof(s.mat));
72         s.mat[0][0] = 2*a; s.mat[0][1] = b-a*a;
73         s.mat[1][0] = 1; s.mat[1][1] = 0;
74 
75         s = qpow(s, n-1);
76         LL ans = (1LL*s.mat[0][0]*f[1]%MOD+1LL*s.mat[0][1]*f[0]%MOD+2*MOD)%MOD;
77         printf("%lld
", ans);
78     }
79 }
View Code
原文地址:https://www.cnblogs.com/DOLFAMINGO/p/8426441.html