• 【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 }
  • 相关阅读:
    一次心惊肉跳的服务器误删文件的恢复过程
    ThreadPoolExecutor使用详解
    Springboot学习笔记(一)-线程池的简化及使用
    springboot之异步调用@Async
    CentOS 7添加开机启动服务/脚本
    三分钟在任何电脑上使用 chrome os
    Spring Cloud Alibaba基础教程:Sentinel Dashboard中修改规则同步到Nacos
    Nacos部署中的一些常见问题汇总
    Spring Cloud Alibaba基础教程:Sentinel Dashboard中修改规则同步到Apollo
    Spring Cloud Alibaba 新版本发布:众多期待内容整合打包加入!
  • 原文地址:https://www.cnblogs.com/kane0526/p/2811184.html
Copyright © 2020-2023  润新知