HDU 2604 矩阵快速幂

题目大意

给定长度为l的只有f,m两种字母 的序列,问不出现fff,fmf的序列个数有多少个

每次的下一个状态都与前一次状态的后两个字母有关

比如我令mm : 0 , mf : 1 , fm : 2 , ff : 3;

那么dp[i][j] 表示长度为i的序列最后由j状态结尾的总个数,当然 j 要大于2

dp[i][0] = dp[i-1][0] + dp[i-1][2]

dp[i][1] = dp[i-1][0]

dp[i][2] = dp[i-1][1] + dp[i-1][3]

dp[i][3] = dp[i-1][1]

根据这个递推关系,我们就能很容易地用动态规划解这道题目,然后就发现超时了 。。。

换个角度把dp值当作矩阵看 (dp[i][0] ,  dp[i][1] , dp[i][2] , dp[i][3]) = {{1 , 1 , 0 , 0} , {0 , 0 , 1, 1} , {1 , 0 , 0 ,0} , {0 , 0 ,1 , 0}} *(dp[i-1][0] ,  dp[i-1][1] , dp[i-1][2] , dp[i-1][3])

然后连续乘法上进行优化

while(n){

  if(n & 1) ~

  ~

  n>>=1

}

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 using namespace std;
 5 int l , M;
 6
 7 struct Matrix{
 8     int m[4][4];
 9     Matrix operator*(const Matrix &p)const {
10         Matrix tmp;
11         for(int i = 0 ; i < 4 ; i++)
12             for(int j = 0 ; j<4 ; j++){
13                 tmp.m[i][j] = 0;
14                 for(int k = 0 ; k<4 ; k++){
15                     tmp.m[i][j] += m[i][k] * p.m[k][j];
16                     tmp.m[i][j] %= M;
17                 }
18             }
19         return tmp;
20     }
21     void show(){
22         for(int i = 0 ; i<4 ; i++){
23             for(int j = 0 ; j<4 ; j++){
24                 printf("%d " , m[i][j]);
25             }
26             puts("");
27         }
28     }
29 };
30
31 Matrix pow(Matrix a , int n)
32 {
33     Matrix tmp;
34     memset(tmp.m , 0 , sizeof(tmp.m));
35     //建立一个单位矩阵
36     for(int i = 0 ; i<4 ; i++)
37             tmp.m[i][i] = 1;
38
39     while(n){
40         if(n & 1) tmp = tmp*a;
41         a = a * a;
42         n >>= 1;
43     }
44     return tmp;
45 }
46
47 int main()
48 {
49     while(~scanf("%d%d" , &l , &M)){
50         if(l == 0) puts("0");
51         else if(l == 1) printf("%d\n" , 2%M);
52         else{
53             Matrix a;
54             a.m[0][0] = 1 , a.m[0][1] = 1 , a.m[0][2] = 0 , a.m[0][3] = 0;
55             a.m[1][0] = 0 , a.m[1][1] = 0 , a.m[1][2] = 1 , a.m[1][3] = 1;
56             a.m[2][0] = 1 , a.m[2][1] = 0 , a.m[2][2] = 0 , a.m[2][3] = 0;
57             a.m[3][0] = 0 , a.m[3][1] = 0 , a.m[3][2] = 1 , a.m[3][3] = 0;
58
59             Matrix t = pow(a , l-2);
60
61             int ans = 0;
62             int b[4] = {1 , 1 , 1 , 1};
63             for(int i = 0 ; i<4 ; i++)
64                 for(int j = 0 ; j<4 ; j++){
65                     ans += b[j] * t.m[j][i];
66                 }
67             printf("%d\n" , ans % M);
68         }
69     }
70     return 0;
71 }
时间: 2024-10-13 04:32:33

HDU 2604 矩阵快速幂的相关文章

hdu 2604 矩阵快速幂模板题

/* 矩阵快速幂: 第n个人如果是m,有f(n-1)种合法结果 第n个人如果是f,对于第n-1和n-2个人有四种ff,fm,mf,mm其中合法的只有fm和mm 对于ffm第n-3个人只能是m那么有f(n-4)种 对于fmm那么对于第n-3个人没有限制有f(n-3)种 顾f(n)=f(n-1)+f(n-3)+f(n-4); 求出前四个结果分别是 a[1]=2;a[2]=4;a[3]=6;a[4]=9; A=|a[4],a[3],a[2],a[1]| 可以构造矩阵 |1 1 0 0 | B= |0

HDU 4965 矩阵快速幂

顺手写了下矩阵类模板 利用到矩阵乘法的交换律 (A*B)^n == A * (B*A)^n-1 *B #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> #include <vector> #include <utility> #include <stack> #includ

hdu 4965 矩阵快速幂 矩阵相乘性质

Fast Matrix Calculation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 170    Accepted Submission(s): 99 Problem Description One day, Alice and Bob felt bored again, Bob knows Alice is a gir

HDU 5895 矩阵快速幂+高次幂取模

HDU 5895 Mathematician QSC 题意:已知f(n)=2*f(n-1)+f(n-2), g(n)=∑f(i)²(0<=i<=n), 给出n,x,y,s, 求x^(g(n*y))%(s+1); 思路:OEIS查到了g(n)=f(n)*f(n+1)/2, f(n)可以用矩阵快速幂求得, 有一个定理可以用于高次幂取模 x^n %k=x^(n%phi(k)+phi(k)) %k, 此处phi(x)为欧拉函数,但是在对幂次取模时存在一个除2, 又因为(a/b)%k=(a%bk)/b,

hdu 1757 (矩阵快速幂) 一个简单的问题 一个简单的开始

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1757 题意不难理解,当x小于10的时候,数列f(x)=x,当x大于等于10的时候f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + …… + a9 * f(x-10); 所求的是f(x)取m的模,而x,m,a[0]至a[9]都是输入项 初拿到这道题,最开始想的一般是暴力枚举,通过for循环求出f(x)然后再取模,但是有两个问题,首先f(x)可能特别大,其

HDU 2855 (矩阵快速幂)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2855 题目大意:求$S(n)=\sum_{k=0}^{n}C_{n}^{k}Fibonacci(k)$ 解题思路: 题目挺吓人的.先把完整组合数+Fibonacci展开来. 利用Fibonacci的特性,从第一项开始消啊消,消到只有一个数: $S(0)=f(0)$ $S(1)=f(2)$ $S(2)=f(4)$ $S(n)=f(2*n)$ 这样矩阵快速幂就可以了,特判$n=0$时的情况. 快速幂矩阵

hdu 4549 (矩阵快速幂+费马小定理)

题意:已知F0=a,F1=b,Fn=Fn-1*Fn-2,给你a,b,n求Fn%1000000007的值 思路:我们试着写几组数 F0=a F1=b F2=a*b F3=a*b2 F4=a2*b3 F5=a3*b5 我们发现a,b的系数其实是斐波那契数列,我们只需用矩阵快速幂求出相应系数就行,但是 这个系数随着增长会特别大,这时我们需要利用费马小定理进行降幂处理 费马小定理 ap-1≡1(mod p) 代码: #include <iostream> #include <cmath>

HDU 3221 矩阵快速幂+欧拉函数+降幂公式降幂

装载自:http://www.cnblogs.com/183zyz/archive/2012/05/11/2495401.html 题目让求一个函数调用了多少次.公式比较好推.f[n] = f[n-1]*f[n-2].然后a和b系数都是呈斐波那契规律增长的.需要先保存下来指数.但是太大了.在这里不能用小费马定理.要用降幂公式取模.(A^x)%C=A^(x%phi(C)+phi(C))%C(x>=phi(C)) Phi[C]表示不大于C的数中与C互质的数的个数,可以用欧拉函数来求. 矩阵快速幂也不

hdu 2842(矩阵快速幂+递推)

题意:一个中国环的游戏,规则是一个木棒上有n个环,第一个环是可以随意放上或拆下的,剩下的环x如果想放上或拆下必须前一个环x-1是放上的且前x-2个环全部是拆下的,问n个环最少多少次操作可以全部拆掉. 题解:需要进行递推,首先第一步肯定是要拆第n个环保证操作次数最少,因为后面的环是否存在对前面的环不造成影响,而先拆前面的如果要拆后面的环还是要把前面的放上,f(n)表示拆掉前n个环需要的最少操作次数,先拆第n个要拆前n-2个再拆第n个,花费f(n-2)+1,然后这时是00-0010,要拆第n-1个需