【HDU 1005 && ZOJ 3539】简单矩阵dp

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1005

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3538

1005题目大意:

告诉你f[1]=1, f[2]=1, f[n]=(A*f[n-1]+B*f[n-2])%7;然后输入A,B,n,让你求f[n]。

 

解题思路:

解法1:n比较大,给你这样递推式子一般不可能让你全部求出来,一般是有规律可寻的。只要在递推的过程中发现f[n-1]==f[1],f[n]==f[2],停止递推。把它多少个数循环一次记录下来,然后只需要用n对这个数取余即可。

解法2: 巧用矩阵dp 。 一般的矩阵dp是要你自己推出这个递推式,然后再构造矩阵。这题更简单一些,因为题目已经给好了你递推式,f[1],f[2]为特殊项,这里我们不考虑,把f[3]当做第一项来考虑。

f[3]=A+B,   f[4]=A*(A+B)+B

这里递推式可以分解为两项,可以先把[A B](f[3]的两项)提出来,一般的矩阵dp为2阶,所以这样还是不够的。再观察递推式,求f[n+1]时我们还要用到前面两项,f[n]就在之前,所以我们还要把前面出现的f[n-1]保存下来,即让A对应的为1。这样就可以构造矩阵 | A B | 了。

                               | 1 0 |

【HDU 1005 && ZOJ 3539】简单矩阵dp

构造完矩阵其他的就简单了,简单的矩阵快速幂。

解法一AC代码

View Code

解法二AC代码

View Code
 1 #include <iostream>

 2 #include <cstdio>

 3 #include <cstring>

 4 #include <algorithm>

 5 using namespace std;

 6 

 7 #define mod 7

 8 int  a, b, n;

 9 

10 struct Maxtri

11 {

12      int mat[2][2];

13 };

14 

15 Maxtri A, B;

16 

17 void init()

18 {

19     A.mat[0][0]=1,A.mat[0][1]=0;

20     A.mat[1][0]=0,A.mat[1][1]=1;

21     B.mat[0][0]=a,B.mat[0][1]=b;

22     B.mat[1][0]=1,B.mat[1][1]=0;

23 }

24 

25 

26 Maxtri Maxtri_mul(Maxtri a, Maxtri b)

27 {

28     Maxtri c;

29     for(int i=0; i<2; i++)

30         for(int j=0; j<2; j++)

31         {

32             c.mat[i][j]=0;

33             for(int k=0; k<2; k++)

34             c.mat[i][j]+=(a.mat[i][k]*b.mat[k][j])%mod;

35             c.mat[i][j]%=mod;

36         }

37 

38     return c;

39 }

40 

41 int Maxtri_mi(int b)

42 {

43     Maxtri ans=A, tp=B;

44     while(b)

45     {

46         if(b&1)

47              ans=Maxtri_mul(ans,tp);

48         b>>=1;

49         tp=Maxtri_mul(tp,tp);

50     }

51     return (ans.mat[0][0]+ans.mat[0][1])%mod;

52 }

53 

54 int main()

55 {

56     while(~scanf("%d%d%d",&a,&b,&n))

57     {

58         init();

59         if(a+b+n==0) break;

60         if(n<3)

61         {

62             cout << 1 <<endl; continue;

63         }

64         int ans=Maxtri_mi(n-2);

65         printf("%d\n",ans);

66     }

67     return 0;

68 }

 

3538:

解题思路: A____(a种填法)____B____(b种填法)____C____(c种填法)____C____(d种填法)____D

题目的答案可以转换成a*b*c*d。

这里我令dp[i][0]表示两边字母相同中间有i个位置有多少种填法,dp[i][1]表示两边字母不同中间有i个位置多少种填法。

dp[1][0]=3,dp[1][1]=2,dp[2][0]=6,dp[2][1]=7。

可以找到递推式 dp[i][0]=3*dp[i-1][1];  dp[i][1]=dp[i-1][0]+2*dp[i-1][1];

这里找的构造矩阵是|0 1|

                           |3 2|

还要注意的两点:

1、要特判第一个字符前面和最后一个字符后面的空位置。

2、中间要特判两个字符是否相邻,相邻不符合题目,直接输出0.

View Code
  1 #include <iostream>

  2 #include <cstdio>

  3 #include <cstring>

  4 #include <algorithm>

  5 using namespace std;

  6 

  7 #define mod 1000000007

  8 typedef long long lld;

  9 

 10 struct Node

 11 {

 12     int d;

 13     char str[5];

 14     bool operator<(const Node &S)const

 15     {

 16         return d<S.d;

 17     }

 18 }f[20];

 19 

 20 struct Maxtri

 21 {

 22     lld mat[2][2];

 23 };

 24 

 25 Maxtri A, B;

 26 

 27 void init()

 28 {

 29     A.mat[0][0]=1,A.mat[0][1]=0;

 30     A.mat[1][0]=0,A.mat[1][1]=1;

 31     B.mat[0][0]=0,B.mat[0][1]=1;

 32     B.mat[1][0]=3,B.mat[1][1]=2;

 33 }

 34 

 35 lld Maxtri_mod(lld a, int b)

 36 {

 37     lld ans=1;

 38     while(b)

 39     {

 40         if(b&1)

 41             ans=(ans*a)%mod;

 42         b>>=1;

 43         a=(a*a)%mod;

 44     }

 45     return ans;

 46 }

 47 

 48 Maxtri Maxtri_mul(Maxtri a, Maxtri b)

 49 {

 50     Maxtri c;

 51     for(int i=0; i<2; i++)

 52         for(int j=0; j<2; j++)

 53         {

 54             c.mat[i][j]=0;

 55             for(int k=0; k<2; k++)

 56             c.mat[i][j]+=(a.mat[i][k]*b.mat[k][j])%mod;

 57             c.mat[i][j]%=mod;

 58         }

 59 

 60     return c;

 61 }

 62 

 63 lld Maxtri_mi(int b, int p)

 64 {

 65     Maxtri ans=A, tp=B;

 66     while(b)

 67     {

 68         if(b&1)

 69              ans=Maxtri_mul(ans,tp);

 70         b>>=1;

 71         tp=Maxtri_mul(tp,tp);

 72     }

 73     if(p==0)

 74       return ans.mat[1][0]%mod;

 75     else

 76       return  ans.mat[1][1]%mod;

 77 }

 78 

 79 int main()

 80 {

 81     int n, m;

 82     init();

 83     while(~scanf("%d%d",&n,&m))

 84     {

 85         if(m==0)

 86         {

 87             lld ans=Maxtri_mod(3,n-1)*4%mod;

 88             printf("%lld\n",ans);

 89             continue;

 90         }

 91         for(int i=0; i<m; i++)

 92             scanf("%d %s",&f[i].d,f[i].str);

 93         sort(f,f+m);

 94         lld ans=Maxtri_mod(3,f[0].d-1)%mod;

 95         for(int i=1; i<m; i++)

 96         {

 97             if(f[i].d-f[i-1].d-1==0) ///!!!

 98             {

 99                 if(*f[i].str==*f[i-1].str) 

100                 {

101                      cout << 0 <<endl; goto loop;  ///直接跳出循环到loop

102                 }

103                 else continue;

104             }

105             else

106             {

107                 if(*f[i].str==*f[i-1].str) /// 开始忘记打*号比较值,不打则是比较地址

108                    ans=ans*Maxtri_mi(f[i].d-f[i-1].d-1,0)%mod;

109                 else

110                    ans=ans*Maxtri_mi(f[i].d-f[i-1].d-1,1)%mod;

111             }

112         }

113         ans=ans*Maxtri_mod(3,n-f[m-1].d)%mod;

114         printf("%lld\n",ans);

115         loop:{}

116     }

117     return 0;

118 }

 

 

你可能感兴趣的:(HDU)