zoukankan      html  css  js  c++  java
  • 【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 |

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

    解法一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 }
  • 相关阅读:
    Atitit. visual studio vs2003 vs2005 vs2008  VS2010 vs2012 vs2015新特性 新功能.doc
    Atitit. C#.net clr 2.0  4.0新特性
    Atitit. C#.net clr 2.0  4.0新特性
    Atitit.通过null 参数 反射  动态反推方法调用
    Atitit.通过null 参数 反射  动态反推方法调用
    Atitit..net clr il指令集 以及指令分类  与指令详细说明
    Atitit..net clr il指令集 以及指令分类  与指令详细说明
    Atitit.变量的定义 获取 储存 物理结构 基本类型简化 隐式转换 类型推导 与底层原理 attilaxDSL
    Atitit.变量的定义 获取 储存 物理结构 基本类型简化 隐式转换 类型推导 与底层原理 attilaxDSL
    Atitit.跨语言反射api 兼容性提升与增强 java c#。Net  php  js
  • 原文地址:https://www.cnblogs.com/kane0526/p/2811184.html
Copyright © 2011-2022 走看看